diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/.gitignore b/.gitignore index 0ac6ea0..98996cc 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,13 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /openssh-9.0p1.tar.gz.asc /openssh-9.3p1.tar.gz /openssh-9.3p1.tar.gz.asc +/openssh-9.6p1.tar.gz +/openssh-9.6p1.tar.gz.asc +/openssh-9.8p1.tar.gz +/openssh-9.8p1.tar.gz.asc +/openssh-9.9p1.tar.gz +/openssh-9.9p1.tar.gz.asc +/openssh-10.0p1.tar.gz +/openssh-10.0p1.tar.gz.asc +/openssh-10.2p1.tar.gz +/openssh-10.2p1.tar.gz.asc diff --git a/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..0377e8c 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 b6875ceaca4be9e0de0d6d260d8fcff1772f5fb5 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 01/53] openssh-7.8p1-role-mls + +--- + auth-pam.c | 2 +- + auth-pam.h | 2 +- + auth.h | 3 + + auth2-gss.c | 11 +- + auth2-hostbased.c | 9 + + auth2-pubkey.c | 11 +- + auth2.c | 14 ++ + misc.c | 8 + + monitor.c | 37 ++- + monitor.h | 4 + + monitor_wrap.c | 21 ++ + monitor_wrap.h | 3 + + openbsd-compat/Makefile.in | 3 +- + openbsd-compat/port-linux-sshd.c | 420 +++++++++++++++++++++++++++++++ + openbsd-compat/port-linux.c | 37 +-- + openbsd-compat/port-linux.h | 3 +- + platform.c | 2 +- + sshd-session.c | 3 + + 18 files changed, 551 insertions(+), 42 deletions(-) + create mode 100644 openbsd-compat/port-linux-sshd.c + +diff --git a/auth-pam.c b/auth-pam.c +index 5591f094e..70bcae83a 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -1261,7 +1261,7 @@ is_pam_session_open(void) + * during the ssh authentication process. + */ + int +-do_pam_putenv(char *name, char *value) ++do_pam_putenv(char *name, const char *value) + { + int ret = 1; + char *compound; +diff --git a/auth-pam.h b/auth-pam.h +index 8d801c689..9dd7ae078 100644 +--- a/auth-pam.h ++++ b/auth-pam.h +@@ -33,7 +33,7 @@ u_int do_pam_account(void); + void do_pam_session(struct ssh *); + void do_pam_setcred(void); + void do_pam_chauthtok(void); +-int do_pam_putenv(char *, char *); ++int do_pam_putenv(char *, const char *); + char ** fetch_pam_environment(void); + char ** fetch_pam_child_environment(void); + void free_pam_environment(char **); +diff --git a/auth.h b/auth.h +index 98bb23d4c..83d07ae8b 100644 +--- a/auth.h ++++ b/auth.h +@@ -65,6 +65,9 @@ struct Authctxt { + char *service; + struct passwd *pw; /* set if 'valid' */ + char *style; +#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 75eb4e3a3..f7898ab3e 100644 +--- a/auth2-gss.c ++++ b/auth2-gss.c +@@ -284,6 +284,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) 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 9d8b860eb..976484fc5 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 15ad3000c..c326a69ba 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -204,9 +204,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 b9bb46f59..1345d3257 100644 +--- a/auth2.c ++++ b/auth2.c +@@ -271,6 +271,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) + Authctxt *authctxt = ssh->authctxt; + Authmethod *m = NULL; + char *user = NULL, *service = NULL, *method = NULL, *style = NULL; +#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 ce77ec943..5bed34735 100644 +--- a/misc.c ++++ b/misc.c +@@ -822,6 +822,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) +@@ -837,6 +838,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 a9e854bec..85dc1b1b7 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -110,6 +110,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[] +@@ -184,6 +187,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 +@@ -919,6 +925,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, +@@ -993,6 +1002,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, +@@ -1364,7 +1393,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, +@@ -1395,6 +1424,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 +@@ -1445,7 +1476,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 +@@ -1466,6 +1497,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 3f8a9bea3..9dcd9c293 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 33494b73f..347eb6870 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -453,6 +453,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 c87295388..9b42ddbcb 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -50,6 +50,9 @@ int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, 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 53c87db6d..39531ae77 100644 +--- a/openbsd-compat/Makefile.in ++++ b/openbsd-compat/Makefile.in +@@ -102,7 +102,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 000000000..b9fbe38b7 +--- /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 c1d54f38d..7426f6f79 100644 +--- a/openbsd-compat/port-linux.c ++++ b/openbsd-compat/port-linux.c +@@ -109,37 +109,6 @@ ssh_selinux_getctxbyname(char *pwname) + return sc; + } + +-/* Set the execution context to the default for the specified user */ +-void +-ssh_selinux_setup_exec_context(char *pwname) +-{ +- char *user_ctx = NULL; +- +- if (!ssh_selinux_enabled()) +- return; +- +- debug3("%s: setting execution context", __func__); +- +- user_ctx = ssh_selinux_getctxbyname(pwname); +- if (setexeccon(user_ctx) != 0) { +- switch (security_getenforce()) { +- case -1: +- fatal("%s: security_getenforce() failed", __func__); +- case 0: +- error("%s: Failed to set SELinux execution " +- "context for %s", __func__, pwname); +- break; +- default: +- fatal("%s: Failed to set SELinux execution context " +- "for %s (in enforcing mode)", __func__, pwname); +- } +- } +- if (user_ctx != NULL) +- freecon(user_ctx); +- +- debug3("%s: done", __func__); +-} +- + /* Set the TTY context for the specified user */ + void + ssh_selinux_setup_pty(char *pwname, const char *tty) +@@ -152,7 +121,11 @@ ssh_selinux_setup_pty(char *pwname, const char *tty) + + debug3("%s: setting TTY context on %s", __func__, tty); + +- user_ctx = ssh_selinux_getctxbyname(pwname); ++ if (getexeccon(&user_ctx) != 0) { ++ error_f("getexeccon: %s", strerror(errno)); ++ goto out; ++ } ++ + + /* XXX: should these calls fatal() upon failure in enforcing mode? */ + +diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 959430de1..055c825e4 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -20,9 +20,10 @@ + #ifdef WITH_SELINUX + int ssh_selinux_enabled(void); + void ssh_selinux_setup_pty(char *, const char *); +-void ssh_selinux_setup_exec_context(char *); + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); ++ ++void sshd_selinux_setup_exec_context(char *); + #endif + + #ifdef LINUX_OOM_ADJUST +diff --git a/platform.c b/platform.c +index fd1a7a7c2..bcf1b0491 100644 +--- a/platform.c ++++ b/platform.c +@@ -140,7 +140,7 @@ platform_setusercontext_post_groups(struct passwd *pw) } #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 8979f743b..cb4b0523d 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1306,6 +1306,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.52.0 + diff --git a/openssh-6.6p1-keycat.patch b/0002-openssh-6.6p1-keycat.patch similarity index 76% rename from openssh-6.6p1-keycat.patch rename to 0002-openssh-6.6p1-keycat.patch index 529b508..b196636 100644 --- a/openssh-6.6p1-keycat.patch +++ b/0002-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 5f16fff915643a515adbbd2e0cd12717938e3570 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 02/53] openssh-6.6p1-keycat + +--- + HOWTO.ssh-keycat | 12 ++ + Makefile.in | 8 +- + configure.ac | 6 + + misc.c | 7 + + openbsd-compat/port-linux-sshd.c | 42 +++++- + openbsd-compat/port-linux.h | 1 + + platform.c | 2 +- + ssh-keycat.c | 241 +++++++++++++++++++++++++++++++ + 8 files changed, 312 insertions(+), 7 deletions(-) + create mode 100644 HOWTO.ssh-keycat + create mode 100644 ssh-keycat.c + +diff --git a/HOWTO.ssh-keycat b/HOWTO.ssh-keycat +new file mode 100644 +index 000000000..630ec628c +--- /dev/null ++++ b/HOWTO.ssh-keycat @@ -0,0 +1,12 @@ +The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys +of an user in any environment. This includes environments with @@ -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 ba17a79f0..a3a495c1b 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -23,6 +23,7 @@ SSH_PROGRAM=@bindir@/ssh ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign +SSH_KEYCAT=$(libexecdir)/ssh-keycat + SSHD_SESSION=$(libexecdir)/sshd-session + SSHD_AUTH=$(libexecdir)/sshd-auth SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper - SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ -@@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@ +@@ -58,6 +59,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@ +@@ -75,7 +77,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) + LIBOPENSSH_OBJS=\ + ssh_api.o \ +@@ -252,6 +254,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(P11HELPER_OBJS) ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(CHANNELLIBS) @@ -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: +@@ -439,6 +444,7 @@ install-files: $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT) @@ -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 db5211013..fd632a5a8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3648,6 +3648,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; +@@ -3658,6 +3659,7 @@ AC_ARG_WITH([pam], + ;; + *) + SSHDLIBS="$SSHDLIBS -ldl" ++ KEYCATLIBS="$KEYCATLIBS -ldl" + ;; + esac + fi +@@ -4883,6 +4885,7 @@ AC_ARG_WITH([selinux], + fi ] + ) + AC_SUBST([SSHDLIBS]) ++AC_SUBST([KEYCATLIBS]) + + # Check whether user wants Kerberos 5 support + KRB5_MSG="no" +@@ -5894,6 +5897,9 @@ fi + if test ! -z "${SSHDLIBS}"; then + echo " +for sshd: ${SSHDLIBS}" + fi ++if test ! -z "${KEYCATLIBS}"; then ++echo " +for ssh-keycat: ${KEYCATLIBS}" ++fi + + echo "" + +diff --git a/misc.c b/misc.c +index 5bed34735..7e27a38d1 100644 +--- a/misc.c ++++ b/misc.c +@@ -2921,6 +2921,13 @@ subprocess(const char *tag, const char *command, + 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 b9fbe38b7..4d56745f7 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -52,6 +52,20 @@ extern ServerOptions options; + extern Authctxt *the_authctxt; 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,19 +225,23 @@ 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) - { - security_context_t *ctx; +diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 055c825e4..c004071d1 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -24,6 +24,7 @@ void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); -- if (!ssh_selinux_enabled()) -+ if (!sshd_selinux_enabled()) - return; + void sshd_selinux_setup_exec_context(char *); ++int sshd_selinux_setup_env_variables(void); + #endif - if (getexeccon((security_context_t *)&ctx) != 0) { -diff -up openssh/platform.c.keycat openssh/platform.c ---- openssh/platform.c.keycat 2015-06-24 10:57:50.147849633 +0200 -+++ openssh/platform.c 2015-06-24 10:57:50.160849601 +0200 -@@ -103,7 +103,7 @@ platform_setusercontext(struct passwd *p + #ifdef LINUX_OOM_ADJUST +diff --git a/platform.c b/platform.c +index bcf1b0491..c92a0cba6 100644 +--- a/platform.c ++++ b/platform.c +@@ -55,7 +55,7 @@ platform_setusercontext(struct passwd *pw) { #ifdef WITH_SELINUX /* Cache selinux status for later use */ @@ -199,9 +250,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 000000000..5678be079 +--- /dev/null ++++ b/ssh-keycat.c @@ -0,0 +1,241 @@ +/* + * Redistribution and use in source and binary forms, with or without @@ -444,41 +497,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.52.0 + diff --git a/openssh-6.6p1-allow-ip-opts.patch b/0003-openssh-6.6p1-allow-ip-opts.patch similarity index 67% rename from openssh-6.6p1-allow-ip-opts.patch rename to 0003-openssh-6.6p1-allow-ip-opts.patch index be8d340..ea11b6c 100644 --- a/openssh-6.6p1-allow-ip-opts.patch +++ b/0003-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 7ffeef7e8218c544b6f4a09c5d43e9b748de5a5f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 03/53] openssh-6.6p1-allow-ip-opts + +--- + sshd-session.c | 32 ++++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/sshd-session.c b/sshd-session.c +index cb4b0523d..1c72e664a 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -754,12 +754,32 @@ check_ip_options(struct ssh *ssh) 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.52.0 + diff --git a/openssh-5.9p1-ipv6man.patch b/0004-openssh-5.9p1-ipv6man.patch similarity index 54% rename from openssh-5.9p1-ipv6man.patch rename to 0004-openssh-5.9p1-ipv6man.patch index ece1a73..6ec8afc 100644 --- a/openssh-5.9p1-ipv6man.patch +++ b/0004-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 f653eed40e15c4c521ce683a604b46ed81cade6a Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 04/53] openssh-5.9p1-ipv6man + +--- + ssh.1 | 2 ++ + sshd.8 | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/ssh.1 b/ssh.1 +index 697f4e42a..db92ac9af 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -1663,6 +1663,8 @@ manual page for more information. .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 7fbca776a..0226a8303 100644 +--- a/sshd.8 ++++ b/sshd.8 +@@ -1018,6 +1018,8 @@ concurrently for different ports, this contains the process ID of the one 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.52.0 + diff --git a/0005-openssh-5.8p2-sigpipe.patch b/0005-openssh-5.8p2-sigpipe.patch new file mode 100644 index 0000000..a2a3714 --- /dev/null +++ b/0005-openssh-5.8p2-sigpipe.patch @@ -0,0 +1,26 @@ +From 6ac14fb92cf0d0676f19282f30b9e427025be31b Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 05/53] openssh-5.8p2-sigpipe + +--- + ssh-keyscan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ssh-keyscan.c b/ssh-keyscan.c +index f9788114d..11618ae8a 100644 +--- a/ssh-keyscan.c ++++ b/ssh-keyscan.c +@@ -776,6 +776,9 @@ main(int argc, char **argv) + if (maxfd > fdlim_get(0)) + fdlim_set(maxfd); + fdcon = xcalloc(maxfd, sizeof(con)); ++ ++ signal(SIGPIPE, SIG_IGN); ++ + read_wait = xcalloc(maxfd, sizeof(struct pollfd)); + for (j = 0; j < maxfd; j++) + read_wait[j].fd = -1; +-- +2.52.0 + diff --git a/openssh-7.2p2-x11.patch b/0006-openssh-7.2p2-x11.patch similarity index 68% rename from openssh-7.2p2-x11.patch rename to 0006-openssh-7.2p2-x11.patch index 0a19ecb..dceef7b 100644 --- a/openssh-7.2p2-x11.patch +++ b/0006-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 d6dc5be6e969ecffe30b9972706b3c92d930d81f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 06/53] openssh-7.2p2-x11 + +--- + channels.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/channels.c b/channels.c +index 80014ff34..5ce6bd400 100644 +--- a/channels.c ++++ b/channels.c +@@ -5169,11 +5169,13 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, } 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)); +@@ -5181,11 +5183,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 +@@ -5193,8 +5196,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.52.0 + diff --git a/openssh-5.1p1-askpass-progress.patch b/0007-openssh-5.1p1-askpass-progress.patch similarity index 66% rename from openssh-5.1p1-askpass-progress.patch rename to 0007-openssh-5.1p1-askpass-progress.patch index ff609da..66b351e 100644 --- a/openssh-5.1p1-askpass-progress.patch +++ b/0007-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 c62cd7ce2539c1eac6d0133c07441c617cbc7bc3 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 07/53] openssh-5.1p1-askpass-progress + +--- + contrib/gnome-ssh-askpass2.c | 39 +++++++++++++++++++++++++++++++++--- + 1 file changed, 36 insertions(+), 3 deletions(-) + +diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c +index a62f98152..cb7152dc8 100644 +--- a/contrib/gnome-ssh-askpass2.c ++++ b/contrib/gnome-ssh-askpass2.c +@@ -58,6 +58,7 @@ #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.52.0 + diff --git a/openssh-4.3p2-askpass-grab-info.patch b/0008-openssh-4.3p2-askpass-grab-info.patch similarity index 53% rename from openssh-4.3p2-askpass-grab-info.patch rename to 0008-openssh-4.3p2-askpass-grab-info.patch index 120ed1b..8108482 100644 --- a/openssh-4.3p2-askpass-grab-info.patch +++ b/0008-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 d124ab0f6eea910dc5f03cdd808f6fa792bf2b7a Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 08/53] openssh-4.3p2-askpass-grab-info + +--- + contrib/gnome-ssh-askpass2.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c +index cb7152dc8..bbe93d838 100644 +--- a/contrib/gnome-ssh-askpass2.c ++++ b/contrib/gnome-ssh-askpass2.c +@@ -70,8 +70,12 @@ report_failed_grab (GtkWidget *parent_window, const char *what) 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.52.0 + diff --git a/openssh-7.7p1-redhat.patch b/0009-openssh-8.7p1-redhat.patch similarity index 64% rename from openssh-7.7p1-redhat.patch rename to 0009-openssh-8.7p1-redhat.patch index 1d77f90..8e75aa5 100644 --- a/openssh-7.7p1-redhat.patch +++ b/0009-openssh-8.7p1-redhat.patch @@ -1,6 +1,25 @@ -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 +From c76607384ff077ba1c45759e749562cccaeaa335 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 09/53] openssh-8.7p1-redhat + +--- + ssh_config | 7 +++++++ + ssh_config_redhat | 18 ++++++++++++++++++ + sshd_config | 8 ++++++++ + sshd_config.0 | 6 +++--- + sshd_config.5 | 2 +- + sshd_config_redhat | 18 ++++++++++++++++++ + sshd_config_redhat_cp | 7 +++++++ + 7 files changed, 62 insertions(+), 4 deletions(-) + create mode 100644 ssh_config_redhat + create mode 100644 sshd_config_redhat + create mode 100644 sshd_config_redhat_cp + +diff --git a/ssh_config b/ssh_config +index 238a0c5e3..d9324c957 100644 +--- a/ssh_config ++++ b/ssh_config @@ -43,3 +43,10 @@ # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h @@ -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 000000000..8b1b59021 +--- /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 0f4a3a724..608203e4b 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -10,6 +10,14 @@ + # possible, but leave them commented. Uncommented options override the + # default value. + ++# To modify the system-wide sshd configuration, create a *.conf file under ++# /etc/ssh/sshd_config.d/ which will be automatically included below ++Include /etc/ssh/sshd_config.d/*.conf ++ ++# If you want to change the port on a SELinux system, you have to tell ++# SELinux about this change. ++# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER ++# + #Port 22 + #AddressFamily any + #ListenAddress 0.0.0.0 +diff --git a/sshd_config.0 b/sshd_config.0 +index c63d729a9..8c5217c0b 100644 +--- a/sshd_config.0 ++++ b/sshd_config.0 +@@ -1219,9 +1219,9 @@ DESCRIPTION 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 6ae606f1e..aa9f0af76 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1941,7 +1941,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 000000000..993a28d52 +--- /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 000000000..1d592d13f +--- /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.52.0 + diff --git a/0010-openssh-7.8p1-UsePAM-warning.patch b/0010-openssh-7.8p1-UsePAM-warning.patch new file mode 100644 index 0000000..521abe4 --- /dev/null +++ b/0010-openssh-7.8p1-UsePAM-warning.patch @@ -0,0 +1,41 @@ +From 5f6dbc98a184ce485aef90321ae9fc1ba45293f8 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 10/53] openssh-7.8p1-UsePAM-warning + +--- + sshd-session.c | 4 ++++ + sshd_config | 2 ++ + 2 files changed, 6 insertions(+) + +diff --git a/sshd-session.c b/sshd-session.c +index 1c72e664a..9804dc334 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1103,6 +1103,10 @@ main(int ac, char **av) + "enabled authentication methods"); + } + ++ /* 'UsePAM no' is not supported in our builds */ ++ if (! options.use_pam) ++ logit("WARNING: 'UsePAM no' is not supported in this build and may cause several problems."); ++ + #ifdef WITH_OPENSSL + if (options.moduli_file != NULL) + dh_set_moduli_file(options.moduli_file); +diff --git a/sshd_config b/sshd_config +index 608203e4b..48af6321b 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -89,6 +89,8 @@ AuthorizedKeysFile .ssh/authorized_keys + # If you just want the PAM account and session checks to run without + # PAM authentication, then enable this but set PasswordAuthentication + # and KbdInteractiveAuthentication to 'no'. ++# WARNING: 'UsePAM no' is not supported in this build and may cause several ++# problems. + #UsePAM no + + #AllowAgentForwarding yes +-- +2.52.0 + diff --git a/openssh-8.0p1-gssapi-keyex.patch b/0011-openssh-9.6p1-gssapi-keyex.patch similarity index 67% rename from openssh-8.0p1-gssapi-keyex.patch rename to 0011-openssh-9.6p1-gssapi-keyex.patch index 89bcd0d..2e5b723 100644 --- a/openssh-8.0p1-gssapi-keyex.patch +++ b/0011-openssh-9.6p1-gssapi-keyex.patch @@ -1,37 +1,98 @@ +From c992408da3ca7aeae129c731c7753019a16ed226 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 11/53] openssh-9.6p1-gssapi-keyex + +--- + Makefile.in | 7 +- + auth.c | 3 +- + auth2-gss.c | 52 +++- + auth2-methods.c | 6 + + auth2.c | 2 + + canohost.c | 93 +++++++ + canohost.h | 3 + + clientloop.c | 12 + + configure.ac | 24 ++ + gss-genr.c | 312 ++++++++++++++++++++- + gss-serv-krb5.c | 97 ++++++- + gss-serv.c | 200 ++++++++++++-- + kex-names.c | 60 +++- + kex.c | 35 ++- + kex.h | 34 +++ + kexdh.c | 10 + + kexgen.c | 2 +- + kexgssc.c | 706 ++++++++++++++++++++++++++++++++++++++++++++++++ + kexgsss.c | 601 +++++++++++++++++++++++++++++++++++++++++ + monitor.c | 147 +++++++++- + monitor.h | 2 + + monitor_wrap.c | 57 +++- + monitor_wrap.h | 4 +- + readconf.c | 70 +++++ + readconf.h | 6 + + servconf.c | 46 ++++ + servconf.h | 3 + + session.c | 10 +- + ssh-gss.h | 64 ++++- + ssh.1 | 8 + + ssh.c | 6 +- + ssh_config | 2 + + ssh_config.5 | 58 ++++ + sshconnect2.c | 154 ++++++++++- + sshd-auth.c | 55 +++- + sshd-session.c | 9 +- + sshd.c | 3 +- + sshd_config | 2 + + sshd_config.5 | 31 +++ + sshkey.c | 72 ++++- + sshkey.h | 1 + + 41 files changed, 2993 insertions(+), 76 deletions(-) + create mode 100644 kexgssc.c + create mode 100644 kexgsss.c + diff --git a/Makefile.in b/Makefile.in -index e7549470..b68c1710 100644 +index a3a495c1b..a36eb82ed 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 \ +@@ -108,6 +108,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ kexgexc.o kexgexs.o \ - kexsntrup761x25519.o 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 + sshbuf-io.o misc-agent.o -@@ -125,7 +126,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ +@@ -131,7 +132,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ + auth2-chall.o groupaccess.o \ auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \ - monitor.o monitor_wrap.o auth-krb5.o \ +- monitor.o monitor_wrap.o auth-krb5.o \ ++ monitor.o monitor_wrap.o auth-krb5.o kexgsss.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ + sftp-server.o sftp-common.o \ +@@ -143,7 +144,7 @@ SSHD_AUTH_OBJS=sshd-auth.o \ + serverloop.o auth.o auth2.o auth-options.o session.o auth2-chall.o \ + groupaccess.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ + auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \ - auth2-gss.o gss-serv.o gss-serv-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ + monitor_wrap.o auth-krb5.o \ + audit.o audit-bsm.o audit-linux.o platform.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ - 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: +@@ -554,7 +555,7 @@ regress-prep: ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile REGRESSLIBS=libssh.a $(LIBCOMPAT) --TESTLIBS=$(LIBS) $(CHANNELLIBS) -+TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) +-TESTLIBS=$(LIBS) $(CHANNELLIBS) @TESTLIBS@ ++TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) @TESTLIBS@ regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ -diff -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 8d9404743..d25653ee4 100644 +--- a/auth.c ++++ b/auth.c +@@ -354,7 +354,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) case PERMIT_NO_PASSWD: if (strcmp(method, "publickey") == 0 || strcmp(method, "hostbased") == 0 || @@ -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 f7898ab3e..5b1b9cde3 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 99637a89b..a05908cf3 100644 +--- a/auth2-methods.c ++++ b/auth2-methods.c +@@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey = { + &options.pubkey_authentication + }; + #ifdef GSSAPI ++struct authmethod_cfg methodcfg_gsskeyex = { ++ "gssapi-keyex", ++ NULL, ++ &options.gss_authentication ++}; + struct authmethod_cfg methodcfg_gssapi = { "gssapi-with-mic", NULL, +@@ -76,6 +81,7 @@ static struct authmethod_cfg *authmethod_cfgs[] = { + &methodcfg_none, + &methodcfg_pubkey, + #ifdef GSSAPI ++ &methodcfg_gsskeyex, + &methodcfg_gssapi, + #endif + &methodcfg_passwd, diff --git a/auth2.c b/auth2.c -index 0e776224..1c217268 100644 +index 1345d3257..5a4b932a9 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 28f086e5a..875805c99 100644 --- a/canohost.c +++ b/canohost.c @@ -35,6 +35,99 @@ @@ -360,7 +342,7 @@ index abea9c6e..8e81b519 100644 ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { diff --git a/canohost.h b/canohost.h -index 26d62855..0cadc9f1 100644 +index 26d62855a..0cadc9f18 100644 --- a/canohost.h +++ b/canohost.h @@ -15,6 +15,9 @@ @@ -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 49d048d85..33adf31dc 100644 --- a/clientloop.c +++ b/clientloop.c -@@ -112,6 +112,10 @@ +@@ -107,6 +107,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, +@@ -1604,6 +1608,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 fd632a5a8..adccaebd4 100644 --- a/configure.ac +++ b/configure.ac -@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) +@@ -813,6 +813,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 8f1f54afb..f2d6f59e5 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,169 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) return 0; } @@ -554,19 +527,29 @@ index d56257b4..763a63ff 100644 + for (i = 0; i < gss_supported->count; i++) { + if (gss_supported->elements[i].length < 128 && + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { ++ EVP_MD_CTX * ctx = NULL; ++ EVP_MD *md5 = NULL; /* Here we don't use MD5 for crypto purposes */ ++ unsigned int md_size = sizeof(digest); + + deroid[0] = SSH_GSS_OIDTYPE; + deroid[1] = gss_supported->elements[i].length; -+ -+ if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || -+ (r = ssh_digest_update(md, deroid, 2)) != 0 || -+ (r = ssh_digest_update(md, -+ gss_supported->elements[i].elements, -+ gss_supported->elements[i].length)) != 0 || -+ (r = ssh_digest_final(md, digest, sizeof(digest))) != 0) ++ if ((md5 = EVP_MD_fetch(NULL, "MD5", "provider=default,-fips")) == NULL) ++ fatal_fr(r, "MD5 fetch failed"); ++ if ((ctx = EVP_MD_CTX_new()) == NULL) { ++ EVP_MD_free(md5); ++ fatal_fr(r, "digest ctx failed"); ++ } ++ if (EVP_DigestInit(ctx, md5) <= 0 ++ || EVP_DigestUpdate(ctx, deroid, 2) <= 0 ++ || EVP_DigestUpdate(ctx, gss_supported->elements[i].elements, ++ gss_supported->elements[i].length) <= 0 ++ || EVP_DigestFinal(ctx, digest, &md_size) <= 0) { ++ EVP_MD_free(md5); ++ EVP_MD_CTX_free(ctx); + fatal_fr(r, "digest failed"); -+ ssh_digest_free(md); -+ md = NULL; ++ } ++ EVP_MD_free(md5); md5 = NULL; ++ EVP_MD_CTX_free(ctx); ctx = NULL; + + encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5) + * 2); @@ -645,7 +628,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 +355,7 @@ ssh_gssapi_build_ctx(Gssctxt **ctx) + (*ctx)->creds = GSS_C_NO_CREDENTIAL; + (*ctx)->client = GSS_C_NO_NAME; + (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; ++ (*ctx)->first = 1; + } + + /* Delete our context, providing it has been built correctly */ +@@ -193,6 +381,12 @@ ssh_gssapi_delete_ctx(Gssctxt **ctx) + gss_release_name(&ms, &(*ctx)->client); + if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms, &(*ctx)->client_creds); ++ sshbuf_free((*ctx)->shared_secret); ++ sshbuf_free((*ctx)->server_pubkey); ++ sshbuf_free((*ctx)->server_host_key_blob); ++ sshbuf_free((*ctx)->server_blob); ++ explicit_bzero((*ctx)->hash, sizeof((*ctx)->hash)); ++ BN_clear_free((*ctx)->dh_client_pub); + + free(*ctx); + *ctx = NULL; +@@ -216,7 +410,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, } ctx->major = gss_init_sec_context(&ctx->minor, @@ -654,7 +658,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 +439,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) return (ctx->major); } @@ -698,7 +702,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 +483,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) return (ctx->major); } @@ -718,7 +722,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 +512,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, } int @@ -735,8 +739,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 +531,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 +749,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 +544,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); @@ -816,7 +820,7 @@ index d56257b4..763a63ff 100644 + #endif /* GSSAPI */ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a151bc1e..8d2b677f 100644 +index a151bc1e4..8d2b677f7 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -1,7 +1,7 @@ @@ -956,11 +960,11 @@ index a151bc1e..8d2b677f 100644 #endif /* KRB5 */ diff --git a/gss-serv.c b/gss-serv.c -index ab3a15f0..6ce56e92 100644 +index b0e9c3b49..6bac42931 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */ + /* $OpenBSD: gss-serv.c,v 1.33 2025/09/29 21:30:15 dtucker Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. @@ -968,7 +972,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 +995,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 +1016,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 +1025,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 +1036,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 +1051,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 +1086,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 +1100,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 +1109,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 +1135,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 +1162,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 +1205,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 +1217,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,37 +1254,37 @@ 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 a20ce602a..31e395aa2 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; +@@ -90,9 +94,22 @@ static const struct kexalg kexalgs[] = { #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1}, + { NULL, 0, -1, -1, 0 }, }; +static const struct kexalg gss_kexalgs[] = { +#ifdef GSSAPI -+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, ++ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, ++ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, ++ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, ++ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, ++ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512, KEX_NOT_PQ }, + { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, ++ NID_X9_62_prime256v1, SSH_DIGEST_SHA256, KEX_NOT_PQ }, ++ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, +#endif -+ { NULL, 0, -1, -1}, ++ { NULL, 0, -1, -1, 0}, +}; -char * @@ -1293,16 +1292,9 @@ index ce85f043..574c7609 100644 +static char * +kex_alg_list_internal(char sep, const struct kexalg *algs) { - char *ret = NULL, *tmp; - size_t nlen, rlen = 0; + char *ret = NULL; const struct kexalg *k; - -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = algs; k->name != NULL; k++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(k->name); -@@ -138,6 +156,18 @@ kex_alg_list(char sep) +@@ -104,6 +121,18 @@ kex_alg_list(char sep) return ret; } @@ -1321,7 +1313,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) +@@ -113,6 +142,10 @@ kex_alg_by_name(const char *name) if (strcmp(k->name, name) == 0) return k; } @@ -1332,10 +1324,11 @@ index ce85f043..574c7609 100644 return NULL; } -@@ -315,6 +349,29 @@ kex_assemble_names(char **listp, const char *def, const char *all) +@@ -336,3 +369,26 @@ kex_assemble_names(char **listp, const char *def, const char *all) + free(ret); return r; } - ++ +/* Validate GSS KEX method name list */ +int +kex_gss_names_valid(const char *names) @@ -1358,11 +1351,55 @@ index ce85f043..574c7609 100644 + free(s); + return 1; +} +diff --git a/kex.c b/kex.c +index 814fad947..9a2ce6d88 100644 +--- a/kex.c ++++ b/kex.c +@@ -295,17 +295,37 @@ static int + kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m) + { + int r; ++ int have_key = 0; ++ int ext_count = 2; + - /* - * 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; +@@ -735,6 +755,9 @@ kex_free(struct kex *kex) sshbuf_free(kex->server_version); sshbuf_free(kex->client_pub); sshbuf_free(kex->session_id); @@ -1373,13 +1410,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 55baa6a1e..206ce60ed 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 +1440,12 @@ index a5ae6ac0..fe714141 100644 KEX_MAX }; -@@ -153,6 +162,12 @@ struct kex { +@@ -169,6 +182,13 @@ struct kex { u_int flags; int hash_alg; int ec_nid; +#ifdef GSSAPI ++ Gssctxt *gss; + int gss_deleg_creds; + int gss_trust_dns; + char *gss_host; @@ -1405,18 +1454,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 { - +@@ -196,8 +216,10 @@ int kex_nid_from_name(const char *); + int kex_is_pq_from_name(const char *); int kex_names_valid(const char *); char *kex_alg_list(char); +char *kex_gss_alg_list(char); char *kex_names_cat(const char *, const char *); - int kex_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 *); +@@ -231,6 +253,12 @@ int kexgex_client(struct ssh *); int kexgex_server(struct ssh *); int kex_gen_client(struct ssh *); int kex_gen_server(struct ssh *); @@ -1429,7 +1478,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 *, +@@ -269,6 +297,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, const BIGNUM *, const u_char *, size_t, u_char *, size_t *); @@ -1443,10 +1492,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 191bdced0..6d5a7813d 100644 --- a/kexdh.c +++ b/kexdh.c -@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex) +@@ -50,13 +50,23 @@ kex_dh_keygen(struct kex *kex) { switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: @@ -1471,7 +1520,7 @@ index 67133e33..edaa4676 100644 break; case KEX_DH_GRP18_SHA512: diff --git a/kexgen.c b/kexgen.c -index 69348b96..c0e8c2f4 100644 +index 494d4b233..58edc79ad 100644 --- a/kexgen.c +++ b/kexgen.c @@ -44,7 +44,7 @@ @@ -1485,10 +1534,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 000000000..96f7b6f58 --- /dev/null +++ b/kexgssc.c -@@ -0,0 +1,612 @@ +@@ -0,0 +1,706 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1538,38 +1587,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 */ @@ -1590,523 +1807,449 @@ index 00000000..f6e1405e + fatal_f("Unexpected KEX type %d", kex->kex_type); + } + if (r != 0) { -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + return r; + } ++ return kexgss_init_ctx(ssh, GSS_C_NO_BUFFER); ++} + -+ token_ptr = GSS_C_NO_BUFFER; ++static int ++input_kexgss_hostkey(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *tmp = NULL; ++ size_t tmp_len = 0; ++ int r; + -+ do { -+ debug("Calling gss_init_sec_context"); ++ debug("Received KEXGSS_HOSTKEY"); ++ if (gss->server_host_key_blob) ++ fatal("Server host key received more than once"); ++ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) ++ fatal("Failed to read server host key: %s", ssh_err(r)); ++ if ((gss->server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) ++ fatal("sshbuf_from failed"); ++ return 0; ++} + -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ int r; + -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); ++ debug("Received GSSAPI_CONTINUE"); ++ if (gss->major == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ if (!(gss->major & GSS_S_CONTINUE_NEEDED)) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ return kexgss_init_ctx(ssh, &recv_tok); ++} + -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); ++static int ++input_kexgss_complete(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ u_char c; ++ int r; + -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("failed to send packet: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); ++ debug("Received GSSAPI_COMPLETE"); ++ if (gss->msg_tok.value != NULL) ++ fatal("Received GSSAPI_COMPLETE twice?"); ++ if ((r = sshpkt_getb_froms(ssh, &gss->server_blob)) != 0 || ++ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &gss->msg_tok)) != 0) ++ fatal("Failed to read message: %s", ssh_err(r)); + -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ u_char *tmp = NULL; -+ size_t tmp_len = 0; ++ /* Is there a token included? */ ++ if ((r = sshpkt_get_u8(ssh, &c)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if (c) { ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ /* If we're already complete - protocol error */ ++ if (gss->major == GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); ++ } else { ++ if (gss->major != GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); ++ } ++ if ((r = sshpkt_get_end(ssh)) != 0) ++ fatal("Expecting end of packet."); + -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) -+ fatal("Failed to read server host key: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgss_init_ctx(ssh, &recv_tok); + -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("Failed to read message: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ return kexgss_final(ssh); ++} + -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ if ((r = sshpkt_get_end(ssh)) != 0) { -+ fatal("Expecting end of packet."); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt_get failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); ++static int ++input_kexgss_error(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *msg; ++ int r; ++ ++ debug("Received Error"); ++ if ((r = sshpkt_get_u32(ssh, &gss->major)) != 0 || ++ (r = sshpkt_get_u32(ssh, &gss->minor)) != 0 || ++ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || ++ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt_get failed: %s", ssh_err(r)); ++ fatal("GSSAPI Error: \n%.400s", msg); ++ return 0; ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ ++int ++kexgssgex_client(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ int r; ++ ++ /* Initialise our GSSAPI world */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) ++ fatal("Couldn't identify host exchange"); ++ ++ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ debug("Doing group exchange"); ++ kex->min = DH_GRP_MIN; ++ kex->max = DH_GRP_MAX; ++ kex->nbits = dh_estimate(kex->dh_need * 8); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->min)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->max)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ ++ debug("Wait SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, &input_kexgssgex_group); ++ return 0; ++} ++ ++static int ++kexgssgex_final(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *buf = NULL; ++ struct sshbuf *empty = NULL; ++ struct sshbuf *shared_secret = NULL; ++ BIGNUM *dh_server_pub = NULL; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ int r = SSH_ERR_INTERNAL_ERROR; + + /* + * We _must_ have received a COMPLETE message in reply from the + * server, which will have set server_blob and msg_tok + */ + -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* compute shared secret */ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80) -+ fatal("The received key has MSB of last octet set!"); -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ if (sshbuf_len(server_blob) != 65) -+ fatal("The received NIST-P256 key did not match" -+ "expected length (expected 65, got %zu)", sshbuf_len(server_blob)); -+ -+ if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) -+ fatal("The received NIST-P256 key does not have first octet 0x04"); -+ -+ r = kex_ecdh_dec(kex, server_blob, &shared_secret); -+ break; -+ default: -+ r = SSH_ERR_INVALID_ARGUMENT; -+ break; -+ } -+ if (r != 0) ++ /* 7. C verifies that the key Q_S is valid */ ++ /* 8. C computes shared secret */ ++ if ((buf = sshbuf_new()) == NULL || ++ (r = sshbuf_put_stringb(buf, gss->server_blob)) != 0 || ++ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); + goto out; ++ } ++ sshbuf_free(buf); ++ buf = NULL; + -+ if ((empty = sshbuf_new()) == NULL) { ++ if ((shared_secret = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->client_pub, -+ server_blob, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } + -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, ++ kex->server_version, kex->my, kex->peer, ++ (gss->server_host_key_blob ? gss->server_host_key_blob : empty), ++ kex->min, kex->nbits, kex->max, dh_p, dh_g, pub_key, ++ dh_server_pub, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), ++ hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("Failed to calculate hash: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; + + /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) ++ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) + sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); + -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, &gss->msg_tok); + + if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); ++ ssh_gssapi_credentials_updated(gss); + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + ++ /* Finally derive the keys and send them */ + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); + ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_host_key_blob); ++ gss->server_host_key_blob = NULL; ++ sshbuf_free(gss->server_blob); ++ gss->server_blob = NULL; ++ } +out: + explicit_bzero(hash, sizeof(hash)); -+ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); -+ sshbuf_free(empty); -+ sshbuf_free(server_host_key_blob); -+ sshbuf_free(server_blob); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ BN_clear_free(dh_server_pub); + sshbuf_free(shared_secret); -+ sshbuf_free(kex->client_pub); -+ kex->client_pub = NULL; + return r; +} + -+int -+kexgssgex_client(struct ssh *ssh) ++static int ++kexgssgex_init_ctx(struct ssh *ssh, ++ gss_buffer_desc *token_ptr) +{ + struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, gssbuf, -+ msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ struct sshbuf *buf = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *server_blob = NULL; -+ BIGNUM *dh_server_pub = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ struct sshbuf *empty = NULL; -+ u_char c; ++ Gssctxt *gss = kex->gss; ++ const BIGNUM *pub_key; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags; + int r; + -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); ++ /* Step 2 - call GSS_Init_sec_context() */ ++ debug("Calling gss_init_sec_context"); + -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); ++ gss->major = ssh_gssapi_init_ctx(gss, kex->gss_deleg_creds, ++ token_ptr, &send_tok, &ret_flags); + -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); ++ if (GSS_ERROR(gss->major)) { ++ /* XXX Useless code: Missing send? */ ++ if (send_tok.length != 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("gss_init_context failed"); ++ } + -+ debug("Doing group exchange"); -+ nbits = dh_estimate(kex->dh_need * 8); ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ gss_release_buffer(&gss->minor, token_ptr); + -+ kex->min = DH_GRP_MIN; -+ kex->max = DH_GRP_MAX; -+ kex->nbits = nbits; -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_u32(ssh, nbits)) != 0 || -+ (r = sshpkt_put_u32(ssh, max)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ if (gss->major == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); + -+ if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0) -+ fatal("Error: %s", ssh_err(r)); ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (gss->first) { ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ gss->first = 0; ++ } else { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("failed to send packet: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, &input_kexgss_hostkey); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgssgex_continue); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, &input_kexgssgex_complete); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, &input_kexgss_error); ++ return 0; ++ } ++ /* No data, and not complete */ ++ if (gss->major != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgssgex_init_ctx(ssh, token_ptr); ++ ++ return kexgssgex_final(ssh); ++} ++ ++static int ++input_kexgssgex_group(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ BIGNUM *p = NULL; ++ BIGNUM *g = NULL; ++ int r; ++ ++ debug("Received SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, NULL); + + if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || + (r = sshpkt_get_bignum2(ssh, &g)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("shpkt_get_bignum2 failed: %s", ssh_err(r)); + -+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) ++ if (BN_num_bits(p) < kex->min || BN_num_bits(p) > kex->max) + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ min, BN_num_bits(p), max); ++ kex->min, BN_num_bits(p), kex->max); + + if ((kex->dh = dh_new_group(g, p)) == NULL) + fatal("dn_new_group() failed"); + p = g = NULL; /* belong to kex->dh now */ + -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ DH_get0_key(kex->dh, &pub_key, NULL); ++ 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) { -+ u_char *tmp = NULL; -+ size_t tmp_len = 0; -+ -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set dh_server_pub and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) ++ 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 000000000..8362081ea --- /dev/null +++ b/kexgsss.c -@@ -0,0 +1,482 @@ +@@ -0,0 +1,601 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -2159,33 +2302,18 @@ index 00000000..60bc02de + +extern ServerOptions options; + ++static int input_kexgss_init(int, u_int32_t, struct ssh *); ++static int input_kexgss_continue(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_groupreq(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_init(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_continue(int, u_int32_t, struct ssh *); ++ +int +kexgss_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf = {0, NULL}, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *client_pubkey = NULL; -+ struct sshbuf *server_pubkey = NULL; -+ struct sshbuf *empty = sshbuf_new(); -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ int r; + + /* Initialise GSSAPI */ + @@ -2201,135 +2329,94 @@ index 00000000..60bc02de + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ do { -+ debug("Wait SSH2_MSG_KEXGSS_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (gssbuf.value != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); + -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ default: -+ fatal_f("Unexpected KEX type %d", kex->kex_type); -+ } -+ if (r != 0) -+ goto out; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, &input_kexgss_init); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgss_continue); ++ debug("Wait SSH2_MSG_KEXGSS_INIT"); ++ return 0; ++} + -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++static inline void ++kexgss_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; + -+ /* Calculate the hash early so we can free the -+ * client_pubkey, which has reference to the parent -+ * buffer state->incoming_packet -+ */ -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ client_pubkey, -+ server_pubkey, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ goto out; ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); + -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); + -+ sshbuf_free(client_pubkey); -+ client_pubkey = NULL; ++ if (gss->buf.value == NULL) ++ fatal("No client public key"); + -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} + -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); ++static inline int ++kexgss_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ struct sshbuf *shared_secret = NULL; ++ int r; + -+ gss_release_buffer(&min_status, &recv_tok); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); + -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (gssbuf.value == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || + (r = sshpkt_send(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } + fatal("accept_ctx died"); + } + -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual Authentication flag wasn't set"); + -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) + fatal("Integrity flag wasn't set"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) + fatal("Couldn't get MIC"); + + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 || ++ (r = sshpkt_put_stringb(ssh, gss->server_pubkey)) != 0 || + (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + -+ if (send_tok.length != 0) { ++ if (send_tok->length != 0) { + if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } else { + if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ @@ -2338,13 +2425,19 @@ index 00000000..60bc02de + if ((r = sshpkt_send(ssh)) != 0) + fatal("sshpkt_send failed: %s", ssh_err(r)); + -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ hashlen = gss->hashlen; ++ memcpy(hash, gss->hash, hashlen); ++ explicit_bzero(gss->hash, sizeof(gss->hash)); ++ shared_secret = gss->shared_secret; ++ gss->shared_secret = NULL; + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); @@ -2353,44 +2446,126 @@ index 00000000..60bc02de + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); ++ ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_pubkey); ++ gss->server_pubkey = NULL; ++ } + explicit_bzero(hash, sizeof(hash)); + sshbuf_free(shared_secret); -+ sshbuf_free(client_pubkey); -+ sshbuf_free(server_pubkey); + return r; +} + ++static int ++input_kexgss_init(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *empty; ++ struct sshbuf *client_pubkey = NULL; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ debug("SSH2_MSG_KEXGSS_INIT received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ case KEX_GSS_GRP14_SHA256: ++ case KEX_GSS_GRP16_SHA512: ++ r = kex_dh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_NISTP256_SHA256: ++ r = kex_ecdh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_C25519_SHA256: ++ r = kex_c25519_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ default: ++ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ } ++ if (r != 0) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ /* Calculate the hash early so we can free the ++ * client_pubkey, which has reference to the parent ++ * buffer state->incoming_packet ++ */ ++ gss->hashlen = sizeof(gss->hash); ++ r = kex_gen_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, client_pubkey, gss->server_pubkey, ++ gss->shared_secret, gss->hash, &gss->hashlen); ++ sshbuf_free(empty); ++ sshbuf_free(client_pubkey); ++ if (r != 0) { ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ gss->buf.value = gss->hash; ++ gss->buf.length = gss->hashlen; ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ +int +kexgssgex_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ BIGNUM *dh_client_pub = NULL; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int min = -1, max = -1, nbits = -1; -+ int cmin = -1, cmax = -1; /* client proposal */ -+ struct sshbuf *empty = sshbuf_new(); -+ int r; + + /* Initialise GSSAPI */ + @@ -2398,29 +2573,194 @@ index 00000000..60bc02de + * in the GSSAPI code are no longer available. This kludges them back + * into life + */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ free(mechs); ++ if (!ssh_gssapi_oid_table_ok()) { ++ mechs = ssh_gssapi_server_mechanisms(); ++ free(mechs); ++ } + + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); ++ + debug("Doing group exchange"); -+ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, &input_kexgssgex_groupreq); ++ return 0; ++} ++ ++static inline void ++kexgssgex_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; ++ ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); ++ ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); ++ ++ if (gss->dh_client_pub == NULL) ++ fatal("No client public key"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} ++ ++static inline int ++kexgssgex_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ struct sshbuf *shared_secret = NULL; ++ struct sshbuf *empty = NULL; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("accept_ctx died"); ++ } ++ ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual Authentication flag wasn't set"); ++ ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity flag wasn't set"); ++ ++ /* calculate shared secret */ ++ shared_secret = sshbuf_new(); ++ if (shared_secret == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if ((r = kex_dh_compute_key(kex, gss->dh_client_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, kex->min, kex->nbits, kex->max, dh_p, dh_g, ++ gss->dh_client_pub, pub_key, sshbuf_ptr(shared_secret), ++ sshbuf_len(shared_secret), hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("kexgex_hash failed: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; ++ ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) ++ fatal("Couldn't get MIC"); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || ++ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ if (send_tok->length != 0) { ++ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } else { ++ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt_send failed: %s", ssh_err(r)); ++ ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = gss; ++ else ++ ssh_gssapi_delete_ctx(&kex->gss); ++ ++ /* Finally derive the keys and send them */ ++ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++ /* If this was a rekey, then save out any delegated credentials we ++ * just exchanged. */ ++ if (options.gss_store_rekey) ++ ssh_gssapi_rekey_creds(); ++ ++ if (kex->gss != NULL) ++ BN_clear_free(gss->dh_client_pub); ++ ++out: ++ explicit_bzero(hash, sizeof(hash)); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ sshbuf_free(shared_secret); ++ return r; ++} ++ ++static int ++input_kexgssgex_groupreq(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ const BIGNUM *dh_p, *dh_g; ++ int min = -1, max = -1, nbits = -1; ++ int cmin = -1, cmax = -1; /* client proposal */ ++ int r; ++ ++ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ++ debug("SSH2_MSG_KEXGSS_GROUPREQ received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, NULL); ++ + /* store client proposal to provide valid signature */ + if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 || + (r = sshpkt_get_u32(ssh, &nbits)) != 0 || + (r = sshpkt_get_u32(ssh, &cmax)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); ++ + kex->nbits = nbits; + kex->min = cmin; + kex->max = cmax; @@ -2428,10 +2768,11 @@ index 00000000..60bc02de + max = MIN(DH_GRP_MAX, cmax); + nbits = MAXIMUM(DH_GRP_MIN, nbits); + nbits = MINIMUM(DH_GRP_MAX, nbits); ++ + if (max < min || nbits < min || max < nbits) -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ kex->dh = PRIVSEP(choose_dh(min, nbits, max)); ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", min, nbits, max); ++ ++ kex->dh = mm_choose_dh(min, nbits, max); + if (kex->dh == NULL) { + sshpkt_disconnect(ssh, "Protocol error: no matching group found"); + fatal("Protocol error: no matching group found"); @@ -2448,152 +2789,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 85dc1b1b7..d463d6a9c 100644 --- a/monitor.c +++ b/monitor.c -@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); +@@ -137,6 +137,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 *); @@ -2602,7 +2864,7 @@ index 2ce89fe9..ebf76c7f 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -214,11 +216,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}, @@ -2618,11 +2880,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 */ +@@ -289,6 +298,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 @@ -2632,7 +2894,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 +@@ -341,8 +354,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); @@ -2649,7 +2911,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) +@@ -429,6 +449,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); @@ -2660,7 +2922,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) +@@ -1896,6 +1920,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif @@ -2678,7 +2940,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) +@@ -1987,8 +2022,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) u_char *p; int r; @@ -2689,7 +2951,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) +@@ -2020,8 +2055,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 flags = 0; /* GSI needs this */ int r; @@ -2700,7 +2962,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) +@@ -2041,6 +2076,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); @@ -2708,7 +2970,7 @@ index 2ce89fe9..ebf76c7f 100644 } return (0); } -@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2052,8 +2088,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 ret; int r; @@ -2719,7 +2981,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) +@@ -2079,13 +2115,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) { @@ -2731,17 +2993,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) +@@ -2094,7 +2134,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); @@ -2754,7 +3016,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) +@@ -2102,5 +2146,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -2840,10 +3102,10 @@ index 2ce89fe9..ebf76c7f 100644 #endif /* GSSAPI */ diff --git a/monitor.h b/monitor.h -index 683e5e07..2b1a2d59 100644 +index 9dcd9c293..dbc7e0037 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, @@ -2853,10 +3115,10 @@ index 683e5e07..2b1a2d59 100644 struct ssh; diff --git a/monitor_wrap.c b/monitor_wrap.c -index 001a8fa1..6edb509a 100644 +index 347eb6870..08dc29e12 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) +@@ -1142,13 +1142,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) } int @@ -2873,7 +3135,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) +@@ -1161,6 +1163,59 @@ mm_ssh_gssapi_userok(char *user) debug3_f("user %sauthenticated", authenticated ? "" : "not "); return (authenticated); } @@ -2931,11 +3193,13 @@ index 001a8fa1..6edb509a 100644 +} + #endif /* GSSAPI */ + + /* diff --git a/monitor_wrap.h b/monitor_wrap.h -index 23ab096a..485590c1 100644 +index 9b42ddbcb..12c489c33 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, +@@ -71,8 +71,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 *); @@ -2947,18 +3211,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 d99205944..eab734aaf 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -65,6 +65,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 { +@@ -159,6 +160,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -2990,7 +3255,7 @@ diff -up a/readconf.c.gsskex b/readconf.c #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1113,10 +1128,42 @@ parse_time: +@@ -1326,10 +1341,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -3033,7 +3298,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) +@@ -2698,7 +2745,13 @@ initialize_options(Options * options) options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; options->gss_authentication = -1; @@ -3047,7 +3312,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) +@@ -2863,8 +2916,18 @@ fill_default_options(Options * options) options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3066,7 +3331,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 +@@ -3692,7 +3755,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); @@ -3081,9 +3346,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 942149f9a..b96e3279e 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 */ @@ -3098,18 +3364,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 48ec8c4ec..3b93ca829 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -67,6 +67,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" +@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions *options) options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3121,7 +3388,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 +@@ -374,10 +378,18 @@ fill_default_server_options(ServerOptions *options) options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3140,15 +3407,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, +@@ -562,6 +574,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 { +@@ -647,12 +660,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3171,7 +3438,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 +@@ -1643,6 +1666,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->gss_authentication; goto parse_flag; @@ -3182,7 +3449,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 +@@ -1651,6 +1678,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3205,22 +3472,22 @@ 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) +@@ -3256,7 +3299,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); -+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, diff --git a/servconf.h b/servconf.h -index 4202a2d0..3f47ea25 100644 +index 9beb90fae..c3f501400 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 */ @@ -3233,10 +3500,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 f265fdc3e..b8f0c1a58 100644 --- a/session.c +++ b/session.c -@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +@@ -2630,13 +2630,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) #ifdef KRB5 if (options.kerberos_ticket_cleanup && @@ -3259,18 +3526,10 @@ index 8c0e54f7..06a33442 100644 /* remove agent socket */ diff --git a/ssh-gss.h b/ssh-gss.h -index 36180d07..70dd3665 100644 +index 7b14e74a8..8ec451926 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 @@ -3296,6 +3555,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; @@ -3305,7 +3566,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; @@ -3317,7 +3578,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 *); @@ -3325,12 +3586,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[]; @@ -3338,7 +3609,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 *); @@ -3346,7 +3617,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 *); @@ -3383,24 +3654,26 @@ index 36180d07..70dd3665 100644 #endif /* _SSH_GSS_H */ diff --git a/ssh.1 b/ssh.1 -index 60de6087..db5c65bc 100644 +index db92ac9af..6a9fbdc5b 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), @@ -3408,12 +3681,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 3b03108db..8d27f6379 100644 --- a/ssh.c +++ b/ssh.c -@@ -747,6 +747,8 @@ main(int ac, char **av) +@@ -847,6 +847,8 @@ main(int ac, char **av) else if (strcmp(optarg, "kex") == 0 || strcasecmp(optarg, "KexAlgorithms") == 0) cp = kex_alg_list('\n'); @@ -3422,7 +3695,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) +@@ -877,8 +879,8 @@ main(int ac, char **av) } else if (strcmp(optarg, "help") == 0) { cp = xstrdup( "cipher\ncipher-auth\ncompression\nkex\n" @@ -3434,7 +3707,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 d9324c957..ca7c5853b 100644 --- a/ssh_config +++ b/ssh_config @@ -24,6 +24,8 @@ @@ -3444,13 +3717,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 f7066cbaa..8a4b469cf 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 . @@ -3520,20 +3793,11 @@ index 06a32d31..3f490697 100644 Indicates that .Xr ssh 1 diff --git a/sshconnect2.c b/sshconnect2.c -index af00fb30..03bc87eb 100644 +index b3679c9d7..b253f991b 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) @@ -3544,11 +3808,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 @@ -3584,10 +3847,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 @@ -3606,6 +3870,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) @@ -3618,11 +3883,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 */ @@ -3633,10 +3895,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 *); @@ -3644,7 +3906,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 @@ -3656,7 +3918,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; @@ -3690,7 +3952,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, @@ -3707,7 +3969,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; } @@ -3763,32 +4025,20 @@ 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) +diff --git a/sshd-auth.c b/sshd-auth.c +index 9c31515de..5a4ee733c 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -696,7 +696,7 @@ main(int ac, char **av) + break; + } } - 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) +- if (!have_key) ++ if (!have_key && !options.gss_keyex) + fatal("internal error: received no hostkeys"); + + /* Ensure that umask disallows at least group and world write */ +@@ -819,6 +819,48 @@ do_ssh2_kex(struct ssh *ssh) free(hkalgs); @@ -3815,7 +4065,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; + @@ -3825,7 +4075,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; @@ -3837,11 +4087,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) +@@ -836,6 +878,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; @@ -3853,15 +4102,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 9804dc334..6e28020e9 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -592,8 +592,8 @@ notify_hostkeys(struct ssh *ssh) + } + debug3_f("sent %u hostkeys", nkeys); + if (nkeys == 0) +- fatal_f("no hostkeys"); +- if ((r = sshpkt_send(ssh)) != 0) ++ debug3_f("no hostkeys"); ++ else if ((r = sshpkt_send(ssh)) != 0) + sshpkt_fatal(ssh, r, "%s: send", __func__); + sshbuf_free(buf); + } +@@ -1135,8 +1135,9 @@ main(int ac, char **av) + break; + } + } +- if (!have_key) +- fatal("internal error: monitor received no hostkeys"); ++ /* The GSSAPI key exchange can run without a host key */ ++ if (!have_key && !options.gss_keyex) ++ fatal("internal error: monitor received no hostkeys and GSS KEX is not configured"); + + /* Ensure that umask disallows at least group and world write */ + new_umask = umask(0077) | 0022; +diff --git a/sshd.c b/sshd.c +index 3c76b60b0..3ab81e268 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -1676,7 +1676,8 @@ main(int ac, char **av) + free(fp); + } + accumulate_host_timing_secret(cfg, NULL); +- if (!sensitive_data.have_ssh2_key) { ++ /* The GSSAPI key exchange can run without a host key */ ++ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { + logit("sshd: no hostkeys available -- exiting."); + exit(1); + } diff --git a/sshd_config b/sshd_config -index 19b7c91a..2c48105f 100644 +index 48af6321b..8db9f0fb1 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 @@ -3871,10 +4160,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 aa9f0af76..b90068bf3 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 . @@ -3886,7 +4175,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 . @@ -3920,14 +4209,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 afd7822c4..148fee2b7 100644 --- a/sshkey.c +++ b/sshkey.c -@@ -127,6 +127,75 @@ static const struct keytype keytypes[] = { - extern const struct sshkey_impl sshkey_xmss_impl; - extern const struct sshkey_impl sshkey_xmss_cert_impl; - #endif -+ +@@ -114,6 +114,75 @@ extern const struct sshkey_impl sshkey_rsa_sha512_impl; + extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; + #endif /* WITH_OPENSSL */ + +static int ssh_gss_equal(const struct sshkey *, const struct sshkey *) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; @@ -3996,18 +4284,19 @@ 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_xmss_impl, - &sshkey_xmss_cert_impl, - #endif + &sshkey_ed25519_cert_impl, +@@ -144,6 +213,7 @@ const struct sshkey_impl * const keyimpls[] = { + &sshkey_rsa_sha512_impl, + &sshkey_rsa_sha512_cert_impl, + #endif /* WITH_OPENSSL */ + &sshkey_gss_kex_impl, NULL }; -@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) +@@ -314,7 +384,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]; @@ -4017,10 +4306,10 @@ index 57995ee6..fd5b7724 100644 if (!include_sigonly && impl->sigonly) continue; diff --git a/sshkey.h b/sshkey.h -index 71a3fddc..37a43a67 100644 +index c3262b896..931d1f79b 100644 --- a/sshkey.h +++ b/sshkey.h -@@ -69,6 +69,7 @@ enum sshkey_types { +@@ -67,6 +67,7 @@ enum sshkey_types { KEY_ECDSA_SK_CERT, KEY_ED25519_SK, KEY_ED25519_SK_CERT, @@ -4028,3 +4317,6 @@ index 71a3fddc..37a43a67 100644 KEY_UNSPEC }; +-- +2.52.0 + diff --git a/openssh-6.6p1-force_krb.patch b/0012-openssh-6.6p1-force_krb.patch similarity index 88% rename from openssh-6.6p1-force_krb.patch rename to 0012-openssh-6.6p1-force_krb.patch index 90f8322..70f75fb 100644 --- a/openssh-6.6p1-force_krb.patch +++ b/0012-openssh-6.6p1-force_krb.patch @@ -1,5 +1,17 @@ +From 577b0fea53270292bd0b4979eb5369619b2f5adb Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 12/53] openssh-6.6p1-force_krb + +--- + gss-serv-krb5.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++- + session.c | 23 +++++++ + ssh-gss.h | 4 ++ + sshd.8 | 7 +++ + 4 files changed, 189 insertions(+), 1 deletion(-) + diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 413b845..54dd383 100644 +index 8d2b677f7..14502c5a6 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 b8f0c1a58..3eae5bdf3 100644 --- a/session.c +++ b/session.c -@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command) +@@ -642,6 +642,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 8ec451926..db34d77f4 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 0226a8303..e2d8ff003 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.52.0 + diff --git a/openssh-7.7p1-gssapi-new-unique.patch b/0013-openssh-7.7p1-gssapi-new-unique.patch similarity index 78% rename from openssh-7.7p1-gssapi-new-unique.patch rename to 0013-openssh-7.7p1-gssapi-new-unique.patch index 544932b..89fb40d 100644 --- a/openssh-7.7p1-gssapi-new-unique.patch +++ b/0013-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 1a5b32dbf550467a4ae19351667bcfdf9c52e44d Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 13/53] openssh-7.7p1-gssapi-new-unique + +--- + auth-krb5.c | 262 ++++++++++++++++++++++++++++++++++++++++++------ + auth.h | 3 +- + gss-serv-krb5.c | 42 +++----- + gss-serv.c | 10 +- + servconf.c | 12 ++- + servconf.h | 2 + + session.c | 5 +- + ssh-gss.h | 4 +- + sshd-session.c | 2 +- + sshd_config.5 | 8 ++ + 10 files changed, 279 insertions(+), 71 deletions(-) + +diff --git a/auth-krb5.c b/auth-krb5.c +index 9d2f1f0ea..035032221 100644 +--- a/auth-krb5.c ++++ b/auth-krb5.c @@ -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 83d07ae8b..10e88e11f 100644 +--- a/auth.h ++++ b/auth.h +@@ -85,6 +85,7 @@ struct Authctxt { + krb5_principal krb5_user; + char *krb5_ticket_file; + char *krb5_ccname; ++ int krb5_set_env; + #endif + struct sshbuf *loginmsg; - /* 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 14502c5a6..df55512d3 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, /* 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 6bac42931..d2bc03486 100644 +--- a/gss-serv.c ++++ b/gss-serv.c +@@ -414,13 +414,15 @@ ssh_gssapi_cleanup_creds(void) + } + + /* As user */ +-void ++int + ssh_gssapi_storecreds(void) + { + if (gssapi_client.mech && gssapi_client.mech->storecreds) { +- (*gssapi_client.mech->storecreds)(&gssapi_client); ++ return (*gssapi_client.mech->storecreds)(&gssapi_client); + } else + debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); ++ ++ return 0; + } + + /* This allows GSSAPI methods to do things to the child's environment based +@@ -500,9 +502,7 @@ ssh_gssapi_rekey_creds(void) { + char *envstr; + #endif + +- if (gssapi_client.store.filename == NULL && +- gssapi_client.store.envval == NULL && +- gssapi_client.store.envvar == NULL) ++ if (gssapi_client.store.envval == NULL) + return; + + ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); +diff --git a/servconf.c b/servconf.c +index 3b93ca829..7bf1507df 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -136,6 +136,7 @@ initialize_server_options(ServerOptions *options) 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 +@@ -376,6 +377,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, +@@ -558,7 +561,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, +@@ -649,11 +652,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 +@@ -1662,6 +1667,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) +@@ -3295,6 +3304,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 c3f501400..a4a38d6d7 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 3eae5bdf3..b8a2dae92 100644 +--- a/session.c ++++ b/session.c +@@ -987,7 +987,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 +@@ -1063,7 +1064,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 db34d77f4..a894e23c9 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -116,7 +116,7 @@ typedef struct ssh_gssapi_mech_struct { + int (*dochild) (ssh_gssapi_client *); + int (*userok) (ssh_gssapi_client *, char *); + int (*localname) (ssh_gssapi_client *, char **); +- void (*storecreds) (ssh_gssapi_client *); ++ int (*storecreds) (ssh_gssapi_client *); + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); + } ssh_gssapi_mech; + +@@ -186,7 +186,7 @@ int ssh_gssapi_userok(char *name, struct passwd *, int kex); + OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); + void ssh_gssapi_do_child(char ***, u_int *); + void ssh_gssapi_cleanup_creds(void); +-void ssh_gssapi_storecreds(void); ++int ssh_gssapi_storecreds(void); + const char *ssh_gssapi_displayname(void); + + char *ssh_gssapi_server_mechanisms(void); +diff --git a/sshd-session.c b/sshd-session.c +index 6e28020e9..028d5850e 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1327,7 +1327,7 @@ main(int ac, char **av) #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 b90068bf3..cae0fd0b4 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1032,6 +1032,14 @@ Specifies whether to automatically destroy the user's ticket cache 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.52.0 + diff --git a/openssh-7.2p2-k5login_directory.patch b/0014-openssh-7.2p2-k5login_directory.patch similarity index 74% rename from openssh-7.2p2-k5login_directory.patch rename to 0014-openssh-7.2p2-k5login_directory.patch index 80e7678..fa07e55 100644 --- a/openssh-7.2p2-k5login_directory.patch +++ b/0014-openssh-7.2p2-k5login_directory.patch @@ -1,8 +1,20 @@ +From 0b19c3dabb1e23837238e90238f1ab5fa3c99df8 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 14/53] openssh-7.2p2-k5login_directory + +--- + auth-krb5.c | 16 ++++++++++++++++ + auth.h | 2 ++ + gss-serv-krb5.c | 21 ++++++++++++++++++++- + sshd.8 | 4 ++++ + 4 files changed, 42 insertions(+), 1 deletion(-) + diff --git a/auth-krb5.c b/auth-krb5.c -index 2b02a04..19b9364 100644 +index 035032221..4910aa38a 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 10e88e11f..391630350 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 df55512d3..820f794cf 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 e2d8ff003..fa33f5232 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.52.0 + diff --git a/openssh-6.6p1-kuserok.patch b/0015-openssh-6.6p1-kuserok.patch similarity index 79% rename from openssh-6.6p1-kuserok.patch rename to 0015-openssh-6.6p1-kuserok.patch index eaf4453..a403c7c 100644 --- a/openssh-6.6p1-kuserok.patch +++ b/0015-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 d0c2e8ddde548c79144547152b523346ae9f0358 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 15/53] openssh-6.6p1-kuserok + +--- + auth-krb5.c | 20 ++++++++- + gss-serv-krb5.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++-- + servconf.c | 13 +++++- + servconf.h | 1 + + sshd_config | 1 + + sshd_config.5 | 5 +++ + 6 files changed, 139 insertions(+), 7 deletions(-) + +diff --git a/auth-krb5.c b/auth-krb5.c +index 4910aa38a..b9c261a24 100644 +--- a/auth-krb5.c ++++ b/auth-krb5.c +@@ -55,6 +55,21 @@ 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 820f794cf..187faf929 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -66,6 +66,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, 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 7bf1507df..8f4b2b43e 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -143,6 +143,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; +@@ -393,6 +394,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, +@@ -561,7 +564,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, +@@ -653,12 +656,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; - +@@ -2431,6 +2436,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 " +@@ -2997,6 +3006,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) +@@ -3305,6 +3315,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 a4a38d6d7..11de36a23 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 8db9f0fb1..ea5a878e6 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -75,6 +75,7 @@ AuthorizedKeysFile .ssh/authorized_keys + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no ++#KerberosUseKuserok yes + + # GSSAPI options + #GSSAPIAuthentication no +diff --git a/sshd_config.5 b/sshd_config.5 +index cae0fd0b4..c360fcfff 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1040,6 +1040,10 @@ The default value .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. +@@ -1354,6 +1358,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.52.0 + diff --git a/0016-openssh-6.4p1-fromto-remote.patch b/0016-openssh-6.4p1-fromto-remote.patch new file mode 100644 index 0000000..2a2575e --- /dev/null +++ b/0016-openssh-6.4p1-fromto-remote.patch @@ -0,0 +1,28 @@ +From d755d647c33f96cd4ec7d5499d11ecd443bdb098 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 16/53] openssh-6.4p1-fromto-remote + +--- + scp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/scp.c b/scp.c +index c5f573cc1..d97a54cc4 100644 +--- a/scp.c ++++ b/scp.c +@@ -1148,7 +1148,10 @@ toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) + addargs(&alist, "%s", ssh_program); + addargs(&alist, "-x"); + addargs(&alist, "-oClearAllForwardings=yes"); +- addargs(&alist, "-n"); ++ if (isatty(fileno(stdin))) ++ addargs(&alist, "-t"); ++ else ++ addargs(&alist, "-n"); + for (j = 0; j < remote_remote_args.num; j++) { + addargs(&alist, "%s", + remote_remote_args.list[j]); +-- +2.52.0 + diff --git a/openssh-6.6.1p1-log-in-chroot.patch b/0017-openssh-6.6.1p1-log-in-chroot.patch similarity index 53% rename from openssh-6.6.1p1-log-in-chroot.patch rename to 0017-openssh-6.6.1p1-log-in-chroot.patch index 941c694..6704616 100644 --- a/openssh-6.6.1p1-log-in-chroot.patch +++ b/0017-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 674851677d1e38cf6992948f8f452e46107a2014 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 17/53] openssh-6.6.1p1-log-in-chroot + +--- + log.c | 11 +++++++++-- + log.h | 1 + + monitor.c | 17 +++++++++++++++-- + monitor.h | 2 +- + session.c | 26 +++++++++++++++----------- + sftp-server-main.c | 2 +- + sftp-server.c | 6 +++--- + sftp.h | 2 +- + sshd-session.c | 7 ++++++- + 9 files changed, 52 insertions(+), 22 deletions(-) + +diff --git a/log.c b/log.c +index 5969c4a16..49b0c8a68 100644 +--- a/log.c ++++ b/log.c +@@ -196,6 +196,11 @@ void 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 8e8dfc23f..70048a8af 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 d463d6a9c..453469665 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -2007,9 +2007,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 dbc7e0037..d4d631ddc 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 b8a2dae92..d034f5c65 100644 +--- a/session.c ++++ b/session.c +@@ -162,6 +162,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 +@@ -632,6 +633,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 +@@ -691,6 +693,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) +@@ -1469,14 +1475,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 +@@ -1609,8 +1607,6 @@ do_child(struct ssh *ssh, Session *s, const char *command) exit(1); } @@ -168,10 +153,10 @@ 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 - argv[i] = NULL; - optind = optreset = 1; - __progname = argv[0]; +@@ -1638,9 +1634,17 @@ do_child(struct ssh *ssh, Session *s, const char *command) + #ifdef WITH_SELINUX + ssh_selinux_change_context("sftpd_t"); + #endif - exit(sftp_server_main(i, argv, s->pw)); + exit(sftp_server_main(i, argv, s->pw, have_dev_log)); } @@ -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 2c70f89bc..bbb79f278 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 777821acd..185ad1459 100644 +--- a/sftp-server.c ++++ b/sftp-server.c +@@ -1897,7 +1897,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; +@@ -1909,7 +1909,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, +@@ -1982,7 +1982,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 2bde8bb7f..ddf1a3968 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 028d5850e..4a5eaa1ff 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -415,7 +415,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 +@@ -434,6 +434,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.52.0 + diff --git a/0018-openssh-6.6.1p1-scp-non-existing-directory.patch b/0018-openssh-6.6.1p1-scp-non-existing-directory.patch new file mode 100644 index 0000000..e50e1c2 --- /dev/null +++ b/0018-openssh-6.6.1p1-scp-non-existing-directory.patch @@ -0,0 +1,27 @@ +From 931f22f77ab2b9cebd96e113f1e3ab179dd1b6cb Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 18/53] openssh-6.6.1p1-scp-non-existing-directory + +--- + scp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/scp.c b/scp.c +index d97a54cc4..e1992622f 100644 +--- a/scp.c ++++ b/scp.c +@@ -1866,6 +1866,10 @@ sink(int argc, char **argv, const char *src) + free(vect[0]); + continue; + } ++ if (buf[0] == 'C' && ! exists && np[strlen(np)-1] == '/') { ++ errno = ENOTDIR; ++ goto bad; ++ } + omode = mode; + mode |= S_IWUSR; + if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) { +-- +2.52.0 + diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/0019-openssh-6.6p1-GSSAPIEnablek5users.patch similarity index 62% rename from openssh-6.6p1-GSSAPIEnablek5users.patch rename to 0019-openssh-6.6p1-GSSAPIEnablek5users.patch index cccb3e0..4c0a60b 100644 --- a/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/0019-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 ef91c84a26a282adaf95e165ebcdd44a410c4328 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 19/53] openssh-6.6p1-GSSAPIEnablek5users + +--- + gss-serv-krb5.c | 3 +-- + servconf.c | 13 ++++++++++++- + servconf.h | 1 + + sshd_config | 1 + + sshd_config.5 | 6 ++++++ + 5 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 187faf929..03188d9b3 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -278,7 +278,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, 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 8f4b2b43e..5e40f1b00 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -144,6 +144,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; +@@ -396,6 +397,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, +@@ -579,7 +582,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 { +@@ -675,6 +678,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 }, +@@ -683,6 +687,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 +@@ -2440,6 +2445,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 " +@@ -3007,6 +3016,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) +@@ -3316,6 +3326,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 11de36a23..c08cf6a7a 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -152,6 +152,7 @@ typedef struct { + int kerberos_unique_ccache; /* If true, the acquired ticket will + * be stored in per-session ccache */ 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 ea5a878e6..33713c886 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -82,6 +82,7 @@ AuthorizedKeysFile .ssh/authorized_keys + #GSSAPICleanupCredentials yes + #GSSAPIStrictAcceptorCheck yes + #GSSAPIKeyExchange no ++#GSSAPIEnablek5users no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will +diff --git a/sshd_config.5 b/sshd_config.5 +index c360fcfff..a0fc6064f 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -739,6 +739,12 @@ Specifies whether to automatically destroy the user's credentials cache 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.52.0 + diff --git a/0020-openssh-6.8p1-sshdT-output.patch b/0020-openssh-6.8p1-sshdT-output.patch new file mode 100644 index 0000000..ed2379e --- /dev/null +++ b/0020-openssh-6.8p1-sshdT-output.patch @@ -0,0 +1,25 @@ +From cce18d636f4137a4e5401170538868b8b80651c1 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 20/53] openssh-6.8p1-sshdT-output + +--- + servconf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/servconf.c b/servconf.c +index 5e40f1b00..b63a7f0b0 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -3368,7 +3368,7 @@ dump_config(ServerOptions *o) + dump_cfg_string(sXAuthLocation, o->xauth_location); + dump_cfg_string(sCiphers, o->ciphers); + dump_cfg_string(sMacs, o->macs); +- dump_cfg_string(sBanner, o->banner); ++ dump_cfg_string(sBanner, o->banner != NULL ? o->banner : "none"); + dump_cfg_string(sForceCommand, o->adm_forced_command); + dump_cfg_string(sChrootDirectory, o->chroot_directory); + dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); +-- +2.52.0 + diff --git a/openssh-6.7p1-sftp-force-permission.patch b/0021-openssh-6.7p1-sftp-force-permission.patch similarity index 72% rename from openssh-6.7p1-sftp-force-permission.patch rename to 0021-openssh-6.7p1-sftp-force-permission.patch index 1cfa309..737430d 100644 --- a/openssh-6.7p1-sftp-force-permission.patch +++ b/0021-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 57ae33c2f43425725345c910d90ef6fed75d3b85 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 21/53] openssh-6.7p1-sftp-force-permission + +--- + sftp-server.8 | 7 +++++++ + sftp-server.c | 24 ++++++++++++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/sftp-server.8 b/sftp-server.8 +index 5311bf929..5e6e3aa44 100644 +--- a/sftp-server.8 ++++ b/sftp-server.8 @@ -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 185ad1459..e04fc63b3 100644 +--- a/sftp-server.c ++++ b/sftp-server.c +@@ -72,6 +72,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) +@@ -741,6 +745,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) +@@ -750,6 +755,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) +@@ -771,6 +780,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) +@@ -1890,7 +1901,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, +@@ -1914,7 +1925,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, +@@ -1976,6 +1987,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.52.0 + diff --git a/openssh-7.2p2-s390-closefrom.patch b/0022-openssh-7.2p2-s390-closefrom.patch similarity index 66% rename from openssh-7.2p2-s390-closefrom.patch rename to 0022-openssh-7.2p2-s390-closefrom.patch index 363538c..fa59fd6 100644 --- a/openssh-7.2p2-s390-closefrom.patch +++ b/0022-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 25b593f41fa85bcaf1bbdc9c368325c4af033208 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 22/53] openssh-7.2p2-s390-closefrom --- - openbsd-compat/bsd-closefrom.c | 26 ++++++++++++++++++++++++++ + openbsd-compat/bsd-closefrom.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) +diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c +index 49a4f35ff..f61124585 100644 --- a/openbsd-compat/bsd-closefrom.c +++ b/openbsd-compat/bsd-closefrom.c -@@ -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.52.0 diff --git a/openssh-7.6p1-cleanup-selinux.patch b/0023-openssh-7.6p1-cleanup-selinux.patch similarity index 59% rename from openssh-7.6p1-cleanup-selinux.patch rename to 0023-openssh-7.6p1-cleanup-selinux.patch index f7cd50f..d018772 100644 --- a/openssh-7.6p1-cleanup-selinux.patch +++ b/0023-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 4cacb1bda51a2d91cf4cc1c8058b989dfc0c58c8 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 23/53] openssh-7.6p1-cleanup-selinux + +--- + auth2-pubkey.c | 8 ++++-- + misc.c | 5 ++-- + misc.h | 2 +- + openbsd-compat/port-linux-sshd.c | 42 +++++++++++++++++--------------- + openbsd-compat/port-linux.h | 5 ++-- + platform.c | 6 ++++- + sshconnect.c | 2 +- + sshd-auth.c | 2 +- + sshd-session.c | 6 +++-- + 9 files changed, 46 insertions(+), 32 deletions(-) + +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index c326a69ba..b7300ca9e 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -75,6 +75,8 @@ /* 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 +@@ -483,7 +485,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 +@@ -759,7 +762,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 7e27a38d1..2fd14159d 100644 +--- a/misc.c ++++ b/misc.c +@@ -2788,7 +2788,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 +@@ -2922,7 +2923,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 f3c5a18c6..8cdfd7cec 100644 +--- a/misc.h ++++ b/misc.h +@@ -124,7 +124,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 4d56745f7..ab083a637 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -48,10 +48,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 +@@ -221,7 +217,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, +@@ -239,8 +236,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, +@@ -248,7 +245,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, +@@ -270,7 +267,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, +@@ -331,7 +328,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 +@@ -340,11 +338,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 +@@ -360,9 +358,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) +@@ -372,25 +371,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 +@@ -406,7 +408,7 @@ sshd_selinux_setup_exec_context(char *pwname) debug3_f("setting execution context"); @@ -213,66 +218,51 @@ 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 c004071d1..26c5f773b 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -23,8 +23,9 @@ void ssh_selinux_setup_pty(char *, const char *); + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); + +-void sshd_selinux_setup_exec_context(char *); +-int sshd_selinux_setup_env_variables(void); ++int sshd_selinux_enabled(void); ++void sshd_selinux_setup_exec_context(char *, int, int(char *, const char *), void *, int); ++int sshd_selinux_setup_env_variables(int inetd, void *); + #endif + + #ifdef LINUX_OOM_ADJUST +diff --git a/platform.c b/platform.c +index c92a0cba6..66d0c2a6b 100644 +--- a/platform.c ++++ b/platform.c +@@ -33,6 +33,8 @@ + #include "openbsd-compat/openbsd-compat.h" - 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 912a520c5..babe4a982 100644 +--- a/sshconnect.c ++++ b/sshconnect.c +@@ -917,7 +917,7 @@ load_hostkeys_command(struct hostkeys *hostkeys, const char *command_template, if ((pid = subprocess(tag, command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH| @@ -281,3 +271,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 5a4ee733c..f3c38a7d1 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -120,7 +120,7 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE; + int debug_flag = 0; + + /* Flag indicating that the daemon is being started from inetd. */ +-static int inetd_flag = 0; ++int inetd_flag = 0; + + /* Saved arguments to main(). */ + static char **saved_argv; +diff --git a/sshd-session.c b/sshd-session.c +index 4a5eaa1ff..d6bece941 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -130,7 +130,7 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE; + int debug_flag = 0; + + /* Flag indicating that the daemon is being started from inetd. */ +-static int inetd_flag = 0; ++int inetd_flag = 0; + + /* debug goes to stderr unless inetd_flag is set */ + static int log_stderr = 0; +@@ -1337,7 +1337,9 @@ main(int ac, char **av) + } + #endif + #ifdef WITH_SELINUX +- sshd_selinux_setup_exec_context(authctxt->pw->pw_name); ++ sshd_selinux_setup_exec_context(authctxt->pw->pw_name, ++ inetd_flag, do_pam_putenv, the_authctxt, ++ options.use_pam); + #endif + #ifdef USE_PAM + if (options.use_pam) { +-- +2.52.0 + diff --git a/0024-openssh-7.5p1-sandbox.patch b/0024-openssh-7.5p1-sandbox.patch new file mode 100644 index 0000000..32b56db --- /dev/null +++ b/0024-openssh-7.5p1-sandbox.patch @@ -0,0 +1,58 @@ +From 503297ec6f6eef3bb4906271d170fab848e27298 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 24/53] openssh-7.5p1-sandbox + +--- + sandbox-seccomp-filter.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index a0692dd2f..e0f2d4289 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -305,6 +305,9 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_exit_group + SC_ALLOW(__NR_exit_group), + #endif ++#if defined(__NR_flock) && defined(__s390__) ++ SC_ALLOW(__NR_flock), ++#endif + #ifdef __NR_futex + SC_FUTEX(__NR_futex), + #endif +@@ -323,6 +326,21 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_getpid + SC_ALLOW(__NR_getpid), + #endif ++#ifdef __NR_getuid ++ SC_ALLOW(__NR_getuid), ++#endif ++#ifdef __NR_getuid32 ++ SC_ALLOW(__NR_getuid32), ++#endif ++#ifdef __NR_geteuid ++ SC_ALLOW(__NR_geteuid), ++#endif ++#ifdef __NR_geteuid32 ++ SC_ALLOW(__NR_geteuid32), ++#endif ++#ifdef __NR_gettid ++ SC_ALLOW(__NR_gettid), ++#endif + #ifdef __NR_getrandom + SC_ALLOW(__NR_getrandom), + #endif +@@ -332,6 +350,9 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_gettimeofday + SC_ALLOW(__NR_gettimeofday), + #endif ++#if defined(__NR_ipc) && defined(__s390__) ++ SC_ALLOW(__NR_ipc), ++#endif + #ifdef __NR_getuid + SC_ALLOW(__NR_getuid), + #endif +-- +2.52.0 + diff --git a/openssh-7.8p1-scp-ipv6.patch b/0025-openssh-7.8p1-scp-ipv6.patch similarity index 51% rename from openssh-7.8p1-scp-ipv6.patch rename to 0025-openssh-7.8p1-scp-ipv6.patch index 8ae0948..d1eb51a 100644 --- a/openssh-7.8p1-scp-ipv6.patch +++ b/0025-openssh-7.8p1-scp-ipv6.patch @@ -1,8 +1,17 @@ +From e1d86d265d9543c77fa90a33acc70246e68bf3bf Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 25/53] openssh-7.8p1-scp-ipv6 + +--- + scp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + diff --git a/scp.c b/scp.c -index 60682c68..9344806e 100644 +index e1992622f..621131ffc 100644 --- a/scp.c +++ b/scp.c -@@ -714,7 +714,9 @@ toremote(int argc, char **argv) +@@ -1169,7 +1169,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.52.0 diff --git a/openssh-8.0p1-crypto-policies.patch b/0026-openssh-8.0p1-crypto-policies.patch similarity index 87% rename from openssh-8.0p1-crypto-policies.patch rename to 0026-openssh-8.0p1-crypto-policies.patch index 86c08db..5162ffa 100644 --- a/openssh-8.0p1-crypto-policies.patch +++ b/0026-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 6d9e08f061451f6cd464af5ec598fa99d15acadb Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 26/53] openssh-8.0p1-crypto-policies + +--- + ssh_config.5 | 164 ++++++++++++++++++++------------------------- + sshd_config.5 | 179 +++++++++++++++++++------------------------------- + 2 files changed, 140 insertions(+), 203 deletions(-) + +diff --git a/ssh_config.5 b/ssh_config.5 +index 8a4b469cf..8ac5e1633 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -438,17 +438,13 @@ A single argument of 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 @@ +@@ -1360,6 +1357,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 +@@ -1368,29 +1370,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 +@@ -1506,37 +1496,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 @@ +@@ -1725,39 +1711,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 @@ +@@ -2504,7 +2482,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 a0fc6064f..c172d5aab 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 @@ +@@ -1051,6 +1024,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 +@@ -1059,16 +1037,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 @@ +@@ -1105,14 +1083,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 @@ +@@ -1199,21 +1169,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 @@ +@@ -1256,15 +1231,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 @@ +@@ -1751,36 +1717,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 @@ +@@ -2281,7 +2236,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.52.0 + diff --git a/0027-openssh-8.0p1-openssl-kdf.patch b/0027-openssh-8.0p1-openssl-kdf.patch new file mode 100644 index 0000000..6f7f49b --- /dev/null +++ b/0027-openssh-8.0p1-openssl-kdf.patch @@ -0,0 +1,157 @@ +From d73633dd9770bea0c3802075842398faf3e55e30 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 27/53] openssh-8.0p1-openssl-kdf + +--- + configure.ac | 1 + + kex.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 108 insertions(+) + +diff --git a/configure.ac b/configure.ac +index adccaebd4..805be4b5e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3182,6 +3182,7 @@ if test "x$openssl" = "xyes" ; then + HMAC_CTX_init \ + RSA_generate_key_ex \ + RSA_get_default_method \ ++ EVP_KDF_CTX_new \ + ]) + + # OpenSSL_add_all_algorithms may be a macro. +diff --git a/kex.c b/kex.c +index 9a2ce6d88..5f9530908 100644 +--- a/kex.c ++++ b/kex.c +@@ -38,6 +38,11 @@ + #ifdef WITH_OPENSSL + #include + #include ++# ifdef HAVE_EVP_KDF_CTX_NEW ++# include ++# include ++# include ++# endif + #endif + + #include "ssh.h" +@@ -1077,6 +1082,107 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) + return r; + } + ++#ifdef HAVE_EVP_KDF_CTX_NEW ++static const char * ++digest_to_md(int digest_type) ++{ ++ switch (digest_type) { ++ case SSH_DIGEST_SHA1: ++ return SN_sha1; ++ case SSH_DIGEST_SHA256: ++ return SN_sha256; ++ case SSH_DIGEST_SHA384: ++ return SN_sha384; ++ case SSH_DIGEST_SHA512: ++ return SN_sha512; ++ } ++ return NULL; ++} ++ ++static int ++derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, ++ const struct sshbuf *shared_secret, u_char **keyp) ++{ ++ struct kex *kex = ssh->kex; ++ u_char *key = NULL; ++ int r, key_len; ++ ++ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL); ++ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf); ++ OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new(); ++ OSSL_PARAM *params = NULL; ++ const char *md = digest_to_md(kex->hash_alg); ++ char keytype = (char)id; ++ ++ EVP_KDF_free(kdf); ++ if (!ctx) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (md == NULL) { ++ r = SSH_ERR_INVALID_ARGUMENT; ++ goto out; ++ } ++ ++ if (param_bld == NULL) { ++ EVP_KDF_CTX_free(ctx); ++ return -1; ++ } ++ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) { ++ r = SSH_ERR_INVALID_ARGUMENT; ++ goto out; ++ } ++ ++ key_len = ROUNDUP(need, key_len); ++ if ((key = calloc(1, key_len)) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ r = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST, ++ md, strlen(md)) && /* SN */ ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY, ++ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)) && ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_XCGHASH, ++ hash, hashlen) && ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_SESSION_ID, ++ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)) && ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE, ++ &keytype, 1); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ params = OSSL_PARAM_BLD_to_param(param_bld); ++ if (params == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_derive(ctx, key, key_len, params); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++#ifdef DEBUG_KEX ++ fprintf(stderr, "key '%c'== ", id); ++ dump_digest("key", key, key_len); ++#endif ++ *keyp = key; ++ key = NULL; ++ r = 0; ++ ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); ++ free (key); ++ EVP_KDF_CTX_free(ctx); ++ if (r < 0) { ++ return r; ++ } ++ return 0; ++} ++#else + static int + derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + const struct sshbuf *shared_secret, u_char **keyp) +@@ -1140,6 +1246,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + ssh_digest_free(hashctx); + return r; + } ++#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW */ + + #define NKEYS 6 + int +-- +2.52.0 + diff --git a/openssh-8.2p1-visibility.patch b/0028-openssh-8.2p1-visibility.patch similarity index 62% rename from openssh-8.2p1-visibility.patch rename to 0028-openssh-8.2p1-visibility.patch index 89c35ef..7c5eabf 100644 --- a/openssh-8.2p1-visibility.patch +++ b/0028-openssh-8.2p1-visibility.patch @@ -1,8 +1,17 @@ +From ed5e5df9ec7ac96ac2a68c5711db00ed29d4d1cd Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 28/53] openssh-8.2p1-visibility + +--- + regress/misc/sk-dummy/sk-dummy.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c -index dca158de..afdcb1d2 100644 +index 4c96e8827..4af5209db 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, ...) +@@ -80,7 +80,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) +@@ -229,7 +229,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, +@@ -477,7 +477,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, +@@ -534,7 +534,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.52.0 + diff --git a/openssh-8.2p1-x11-without-ipv6.patch b/0029-openssh-8.2p1-x11-without-ipv6.patch similarity index 55% rename from openssh-8.2p1-x11-without-ipv6.patch rename to 0029-openssh-8.2p1-x11-without-ipv6.patch index 8b83bc3..7063d7f 100644 --- a/openssh-8.2p1-x11-without-ipv6.patch +++ b/0029-openssh-8.2p1-x11-without-ipv6.patch @@ -1,12 +1,17 @@ +From c8dce0615eac6d2a724cdb3f288d7aaa1362f65b Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 29/53] openssh-8.2p1-x11-without-ipv6 + +--- + channels.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + diff --git a/channels.c b/channels.c +index 5ce6bd400..26ed9945f 100644 --- a/channels.c +++ b/channels.c -@@ -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) { +@@ -5123,6 +5123,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.52.0 + diff --git a/openssh-8.0p1-preserve-pam-errors.patch b/0030-openssh-8.0p1-preserve-pam-errors.patch similarity index 65% rename from openssh-8.0p1-preserve-pam-errors.patch rename to 0030-openssh-8.0p1-preserve-pam-errors.patch index dbdbe93..4aa2ffb 100644 --- a/openssh-8.0p1-preserve-pam-errors.patch +++ b/0030-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 a3b6182e1d6b69a37a6c841baa43b818251036b1 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 30/53] openssh-8.0p1-preserve-pam-errors + +--- + auth-pam.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/auth-pam.c b/auth-pam.c +index 70bcae83a..70b2b8580 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -551,7 +551,11 @@ sshpam_thread(void *ctxtp) goto auth_fail; if (!do_pam_account()) { @@ -14,9 +24,9 @@ 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) +@@ -608,8 +612,10 @@ sshpam_thread(void *ctxtp) pam_strerror(sshpam_handle, sshpam_err))) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); + fatal_fr(r, "buffer error"); /* XXX - can't do much about an error here */ - if (sshpam_err == PAM_ACCT_EXPIRED) - ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer); @@ -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++; +@@ -913,9 +919,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.52.0 + diff --git a/openssh-8.7p1-scp-kill-switch.patch b/0031-openssh-8.7p1-scp-kill-switch.patch similarity index 52% rename from openssh-8.7p1-scp-kill-switch.patch rename to 0031-openssh-8.7p1-scp-kill-switch.patch index 161ab2d..5c3594f 100644 --- a/openssh-8.7p1-scp-kill-switch.patch +++ b/0031-openssh-8.7p1-scp-kill-switch.patch @@ -1,18 +1,31 @@ -diff -up openssh-8.7p1/pathnames.h.kill-scp openssh-8.7p1/pathnames.h ---- openssh-8.7p1/pathnames.h.kill-scp 2021-09-16 11:37:57.240171687 +0200 -+++ openssh-8.7p1/pathnames.h 2021-09-16 11:42:29.183427917 +0200 -@@ -42,6 +42,7 @@ - #define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" +From ca8b4de1019b859e2c68288a554d1905a6cf029f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 31/53] openssh-8.7p1-scp-kill-switch + +--- + pathnames.h | 1 + + scp.1 | 7 +++++++ + scp.c | 8 ++++++++ + 3 files changed, 16 insertions(+) + +diff --git a/pathnames.h b/pathnames.h +index 0dcc49552..78bba2314 100644 +--- a/pathnames.h ++++ b/pathnames.h +@@ -40,6 +40,7 @@ + #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" #define _PATH_DH_MODULI SSHDIR "/moduli" +#define _PATH_SCP_KILL_SWITCH SSHDIR "/disable_scp" #ifndef _PATH_SSH_PROGRAM #define _PATH_SSH_PROGRAM "/usr/bin/ssh" -diff -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 7bce0fe6f..2bb838c7d 100644 +--- a/scp.1 ++++ b/scp.1 +@@ -334,6 +334,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 621131ffc..3c213f83d 100644 +--- a/scp.c ++++ b/scp.c +@@ -633,6 +633,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.52.0 + diff --git a/0032-openssh-8.7p1-recursive-scp.patch b/0032-openssh-8.7p1-recursive-scp.patch new file mode 100644 index 0000000..adb5e3d --- /dev/null +++ b/0032-openssh-8.7p1-recursive-scp.patch @@ -0,0 +1,200 @@ +From e6478b233cd2298c9e6e6128867421892ff8f0e4 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 32/53] openssh-8.7p1-recursive-scp + +--- + scp.c | 2 +- + sftp-client.c | 60 +++++++++++++++++++++++++++++++++++++++------------ + sftp-client.h | 4 ++-- + sftp.c | 6 +++--- + 4 files changed, 52 insertions(+), 20 deletions(-) + +diff --git a/scp.c b/scp.c +index 3c213f83d..78c79a755 100644 +--- a/scp.c ++++ b/scp.c +@@ -1378,7 +1378,7 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) + + 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 840170ab6..9bf9cc047 100644 +--- a/sftp-client.c ++++ b/sftp-client.c +@@ -1001,7 +1001,7 @@ sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, + + /* 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; +@@ -1047,11 +1047,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); +@@ -1076,9 +1108,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 +@@ -1092,9 +1124,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 +@@ -2014,7 +2046,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 873ad3849..fe58651c1 100644 +--- a/sftp-client.h ++++ b/sftp-client.h +@@ -112,7 +112,7 @@ int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); + int sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); + + /* Canonicalise 'path' - caller must free result */ +-char *sftp_realpath(struct sftp_conn *, const char *); ++char *sftp_realpath(struct sftp_conn *, const char *, int); + + /* Canonicalisation with tilde expansion (requires server extension) */ + char *sftp_expand_path(struct sftp_conn *, const char *); +@@ -164,7 +164,7 @@ int sftp_upload(struct sftp_conn *, const char *, const char *, + * times if 'pflag' is set + */ + int sftp_upload_dir(struct sftp_conn *, const char *, const char *, +- int, int, int, int, int, int); ++ int, int, int, int, int, int, int); + + /* + * Download a 'from_path' from the 'from' connection and upload it to +diff --git a/sftp.c b/sftp.c +index 3b505eea2..2a99698a8 100644 +--- a/sftp.c ++++ b/sftp.c +@@ -801,7 +801,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, + (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, +@@ -1636,7 +1636,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; + } +@@ -2241,7 +2241,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.52.0 + diff --git a/0033-openssh-8.7p1-minrsabits.patch b/0033-openssh-8.7p1-minrsabits.patch new file mode 100644 index 0000000..fcd994b --- /dev/null +++ b/0033-openssh-8.7p1-minrsabits.patch @@ -0,0 +1,37 @@ +From 14f25e21b4e2c5e625f266fcc9af42c2f89845de Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 33/53] openssh-8.7p1-minrsabits + +--- + readconf.c | 1 + + servconf.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/readconf.c b/readconf.c +index eab734aaf..3f67f4de4 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -337,6 +337,7 @@ static struct { + { "securitykeyprovider", oSecurityKeyProvider }, + { "knownhostscommand", oKnownHostsCommand }, + { "requiredrsasize", oRequiredRSASize }, ++ { "rsaminsize", oRequiredRSASize }, /* alias */ + { "enableescapecommandline", oEnableEscapeCommandline }, + { "obscurekeystroketiming", oObscureKeystrokeTiming }, + { "channeltimeout", oChannelTimeout }, +diff --git a/servconf.c b/servconf.c +index b63a7f0b0..ac84b74d9 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -778,6 +778,7 @@ static struct { + { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, + { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, + { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, ++ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ + { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, + { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, + { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, +-- +2.52.0 + diff --git a/0034-openssh-8.7p1-ibmca.patch b/0034-openssh-8.7p1-ibmca.patch new file mode 100644 index 0000000..803c899 --- /dev/null +++ b/0034-openssh-8.7p1-ibmca.patch @@ -0,0 +1,25 @@ +From e2c0fb233119584b04d61d243cd58433072559c2 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 34/53] openssh-8.7p1-ibmca + +--- + openbsd-compat/bsd-closefrom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c +index f61124585..417c20484 100644 +--- a/openbsd-compat/bsd-closefrom.c ++++ b/openbsd-compat/bsd-closefrom.c +@@ -16,7 +16,7 @@ + + #include "includes.h" + +-#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) ++#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) || (defined __s390__) + + #include + #include +-- +2.52.0 + diff --git a/openssh-7.6p1-audit.patch b/0035-openssh-7.6p1-audit.patch similarity index 77% rename from openssh-7.6p1-audit.patch rename to 0035-openssh-7.6p1-audit.patch index 748c4b6..1635f9f 100644 --- a/openssh-7.6p1-audit.patch +++ b/0035-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 c64eb340d925f3f7e29bb1c45b7d7b537ffa6197 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 35/53] openssh-7.6p1-audit + +--- + Makefile.in | 2 +- + audit-bsm.c | 45 ++++++- + audit-linux.c | 302 +++++++++++++++++++++++++++++++++++++++++++--- + audit.c | 129 ++++++++++++++++++-- + audit.h | 22 +++- + auditstub.c | 52 ++++++++ + auth.c | 3 - + auth.h | 4 + + auth2-hostbased.c | 16 ++- + auth2-pubkey.c | 16 ++- + auth2.c | 3 - + cipher.c | 21 +--- + cipher.h | 20 ++- + kex.c | 61 ++++++++-- + kex.h | 2 + + mac.c | 14 +++ + mac.h | 1 + + monitor.c | 193 +++++++++++++++++++++++++++-- + monitor.h | 8 +- + monitor_wrap.c | 130 +++++++++++++++++++- + monitor_wrap.h | 11 +- + packet.c | 98 +++++++++++++-- + packet.h | 1 + + session.c | 82 ++++++++++++- + session.h | 10 +- + sshd-session.c | 98 +++++++++++++-- + sshd.c | 10 ++ + 27 files changed, 1251 insertions(+), 103 deletions(-) + create mode 100644 auditstub.c + +diff --git a/Makefile.in b/Makefile.in +index a36eb82ed..20d134c02 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -110,7 +110,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ + kexgssc.o \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ +- sshbuf-io.o misc-agent.o ++ sshbuf-io.o misc-agent.o auditstub.o + + P11OBJS= ssh-pkcs11-client.o + +diff --git a/audit-bsm.c b/audit-bsm.c +index 4bce22c37..a6292cb8f 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -373,12 +373,25 @@ audit_connection_from(const char *host, int port) #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,8 +91,8 @@ 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 - debug("%s: unhandled event %d", __func__, event); +@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + debug_f("unhandled event %d", event); } } + @@ -71,235 +120,11 @@ 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 -@@ -33,27 +33,40 @@ +diff --git a/audit-linux.c b/audit-linux.c +index 954eabe27..4d3e9d41e 100644 +--- a/audit-linux.c ++++ b/audit-linux.c +@@ -33,29 +33,42 @@ #include "log.h" #include "audit.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; @@ -340,6 +164,8 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c - return 0; /* Must prevent login */ + goto fatal_report; /* Must prevent login */ } + if (hostname != NULL && strcmp(hostname, "UNKNOWN") == 0) + hostname = NULL; - rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, + rc = audit_log_acct_message(audit_fd, event, NULL, "login", username ? username : "(unknown)", @@ -348,7 +174,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 +@@ -67,9 +80,96 @@ linux_audit_record_event(int uid, const char *username, const char *hostname, rc = 0; errno = saved_errno; @@ -446,7 +272,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, +@@ -78,49 +178,211 @@ audit_connection_from(const char *host, int port) /* not implemented */ } @@ -525,6 +351,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: @@ -554,7 +381,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); break; default: - debug("%s: unhandled event %d", __func__, event); + debug_f("unhandled event %d", event); break; } } @@ -564,7 +391,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 +409,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 +488,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 +496,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 dd2f03558..d0433c3a0 100644 +--- a/audit.c ++++ b/audit.c +@@ -34,6 +34,12 @@ + #include "log.h" + #include "hostfile.h" + #include "auth.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "xmalloc.h" ++#include "misc.h" ++#include "servconf.h" ++#include "ssherr.h" + + /* + * Care must be taken when using this since it WILL NOT be initialized when +@@ -41,6 +47,7 @@ + * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. + */ + extern Authctxt *the_authctxt; ++extern ServerOptions options; + + /* Maybe add the audit class to struct Authmethod? */ + ssh_audit_event_t +@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) + const char * + audit_username(void) + { +- static const char unknownuser[] = "(unknown user)"; +- static const char invaliduser[] = "(invalid user)"; ++ static const char unknownuser[] = "(unknown)"; + +- if (the_authctxt == NULL || the_authctxt->user == NULL) ++ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) + return (unknownuser); +- if (!the_authctxt->valid) +- return (invaliduser); + return (the_authctxt->user); + } + +@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) + return(event_lookup[i].name); + } + ++void ++audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) ++{ ++ char *fp; ++ ++ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) ++ *rv = -SSH_ERR_INTERNAL_ERROR; ++ free(fp); ++} ++ ++void ++audit_unsupported(struct ssh *ssh, int what) ++{ ++ mm_audit_unsupported_body(ssh, what); ++} ++ ++void ++audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++ mm_audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid()); ++} ++ ++void ++audit_session_key_free(struct ssh *ssh, int ctos) ++{ ++ mm_audit_session_key_free_body(ssh, ctos, getpid(), getuid()); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. +@@ -137,6 +170,17 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + audit_username(), event, audit_event_lookup(event)); + } + ++/* ++ * Called when a child process has called, or will soon call, ++ * audit_session_open. ++ */ ++void ++audit_count_session_open(void) ++{ ++ debug("audit count session open euid %d user %s", geteuid(), ++ audit_username()); ++} ++ + /* + * Called when a user session is started. Argument is the tty allocated to + * the session, or NULL if no tty was allocated. +@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li) + /* + * This will be called when a user runs a non-interactive command. Note that + * it may be called multiple times for a single connection since SSH2 allows +- * multiple sessions within a single connection. ++ * multiple sessions within a single connection. Returns a "handle" for ++ * audit_end_command. + */ +-void +-audit_run_command(const char *command) ++int ++audit_run_command(struct ssh *ssh, const char *command) + { + debug("audit run command euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); ++ return 0; ++} ++ ++/* ++ * This will be called when the non-interactive command finishes. Note that ++ * it may be called multiple times for a single connection since SSH2 allows ++ * multiple sessions within a single connection. "handle" should come from ++ * the corresponding audit_run_command. ++ */ ++void ++audit_end_command(struct ssh *ssh, int handle, const char *command) ++{ ++ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), ++ audit_username(), command); ++} ++ ++/* ++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. ++ * ++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. ++ */ ++int ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s fingerprint %s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), ++ fp, rv); ++} ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(struct ssh *ssh, int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, ++ (unsigned)uid); ++} ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on destroy private part of the server key ++ */ ++void ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", ++ geteuid(), fp, (long)pid, (unsigned)uid); + } + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/audit.h b/audit.h +index 38cb5ad31..45d66ccff 100644 +--- a/audit.h ++++ b/audit.h +@@ -26,6 +26,7 @@ + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "sshkey.h" + + struct ssh; + +@@ -45,13 +46,32 @@ enum ssh_audit_event_type { + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN + }; ++ ++enum ssh_audit_kex { ++ SSH_AUDIT_UNSUPPORTED_CIPHER, ++ SSH_AUDIT_UNSUPPORTED_MAC, ++ SSH_AUDIT_UNSUPPORTED_COMPRESSION ++}; + typedef enum ssh_audit_event_type ssh_audit_event_t; + ++int listening_for_clients(void); ++ + void audit_connection_from(const char *, int); + void audit_event(struct ssh *, ssh_audit_event_t); ++void audit_count_session_open(void); + void audit_session_open(struct logininfo *); + void audit_session_close(struct logininfo *); +-void audit_run_command(const char *); ++int audit_run_command(struct ssh *, const char *); ++void audit_end_command(struct ssh *, int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); ++int audit_keyusage(struct ssh *, int, char *, int); ++void audit_key(struct ssh *, int, int *, const struct sshkey *); ++void audit_unsupported(struct ssh *, int); ++void audit_kex(struct ssh *, int, char *, char *, char *, char *); ++void audit_unsupported_body(struct ssh *, int); ++void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(struct ssh *, int ctos); ++void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); + + #endif /* _SSH_AUDIT_H */ +diff --git a/auditstub.c b/auditstub.c +new file mode 100644 +index 000000000..639a798df +--- /dev/null ++++ b/auditstub.c @@ -0,0 +1,52 @@ +/* $Id: auditstub.c,v 1.1 jfch Exp $ */ + @@ -725,32 +781,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 d25653ee4..38c34298e 100644 +--- a/auth.c ++++ b/auth.c +@@ -499,9 +499,6 @@ getpwnamallow(struct ssh *ssh, const char *user) + record_failed_login(ssh, user, + auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); + #endif -#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 391630350..6be52d70b 100644 +--- a/auth.h ++++ b/auth.h +@@ -215,6 +215,8 @@ struct sshkey *get_hostkey_private_by_type(int, int, struct ssh *); + int get_hostkey_index(struct sshkey *, int, struct ssh *); + int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, + u_char **, size_t *, const u_char *, size_t, const char *); ++int hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + + /* Key / cert options linkage to auth layer */ + int auth_activate_options(struct ssh *, struct sshauthopt *); +@@ -240,6 +242,8 @@ int auth_check_authkey_line(struct passwd *, struct sshkey *, + char *, const char *, const char *, const char *, struct sshauthopt **); + int auth_check_authkeys_file(struct passwd *, FILE *, char *, + struct sshkey *, const char *, const char *, struct sshauthopt **); ++int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); + +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index 976484fc5..e9421a868 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -157,7 +157,7 @@ userauth_hostbased(struct ssh *ssh, const char *method) 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 +851,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 b7300ca9e..9f3371c07 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -233,7 +233,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) { +@@ -326,6 +326,20 @@ done: return authenticated; } @@ -804,43 +885,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 5a4b932a9..da24f7bcb 100644 +--- a/auth2.c ++++ b/auth2.c +@@ -310,9 +310,6 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) + authctxt->valid = 0; + /* Invalid user, fake password information */ + authctxt->pw = fakepw(); -#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 5e096cebf..9b42ffb9a 100644 +--- a/cipher.c ++++ b/cipher.c @@ -64,25 +64,6 @@ struct sshcipher_ctx { const struct sshcipher *cipher; }; @@ -867,7 +929,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 * +@@ -411,7 +392,7 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, void cipher_free(struct sshcipher_ctx *cc) { @@ -876,9 +938,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 6533ff2bb..2e05a0210 100644 +--- a/cipher.h ++++ b/cipher.h @@ -47,7 +47,25 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 @@ -906,18 +969,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 5f9530908..44f350ce8 100644 +--- a/kex.c ++++ b/kex.c +@@ -66,6 +66,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); +@@ -820,12 +821,16 @@ kex_start_rekex(struct ssh *ssh) } static int @@ -936,7 +1000,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 +@@ -846,8 +851,12 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) { char *name = match_list(client, server, NULL); @@ -950,7 +1014,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 +@@ -860,12 +869,16 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) } static int @@ -969,7 +1033,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) +@@ -1029,7 +1042,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 +1042,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) +@@ -1044,7 +1057,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) peer[nmac] = NULL; goto out; } @@ -987,7 +1051,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) +@@ -1067,6 +1080,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 +1062,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 +@@ -1336,6 +1353,36 @@ dump_digest(const char *msg, const u_char *digest, int len) } #endif @@ -1035,10 +1099,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 206ce60ed..cb06e85a3 100644 +--- a/kex.h ++++ b/kex.h +@@ -260,6 +260,8 @@ int kexgss_client(struct ssh *); int kexgss_server(struct ssh *); #endif @@ -1047,10 +1112,11 @@ 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 -@@ -239,6 +239,20 @@ mac_clear(struct sshmac *mac) +diff --git a/mac.c b/mac.c +index c95f5ea06..354cfb408 100644 +--- a/mac.c ++++ b/mac.c +@@ -230,6 +230,20 @@ mac_clear(struct sshmac *mac) mac->umac_ctx = NULL; } @@ -1071,32 +1137,22 @@ 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 0b119d7a1..5fb593b9e 100644 +--- a/mac.h ++++ b/mac.h +@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, 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 -@@ -93,6 +93,7 @@ +diff --git a/monitor.c b/monitor.c +index 453469665..b2f501790 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -83,6 +83,7 @@ #include "compat.h" #include "ssh2.h" #include "authfd.h" @@ -1104,16 +1160,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; +@@ -100,6 +101,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 +@@ -144,6 +147,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 +1181,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[] +@@ -204,6 +212,10 @@ struct mon_table mon_dispatch_proto20[] = { #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, @@ -1136,7 +1192,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 +@@ -239,6 +251,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 +1204,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 +@@ -1575,8 +1592,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 +1216,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 +@@ -1585,6 +1604,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 +1225,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 +@@ -1600,14 +1621,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 +1245,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 +@@ -1619,8 +1645,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", +@@ -1708,13 +1732,19 @@ mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw) } static void @@ -1219,7 +1275,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, +@@ -1781,7 +1811,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) error: if (s != NULL) @@ -1228,7 +1284,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 +@@ -1800,7 +1830,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,25 +1293,24 @@ 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 +@@ -1822,6 +1852,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, +@@ -1868,12 +1900,46 @@ mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m) { char *cmd; int r; + Session *s; - debug3("%s entering", __func__); + debug3_f("entering"); if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ + fatal_fr(r, "buffer error"); /* sanity check command, if so how? */ - audit_run_command(cmd); + s = session_new(); @@ -1295,7 +1350,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, +@@ -1946,6 +2012,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) void mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) { @@ -1303,7 +1358,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 +@@ -1953,6 +2020,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 +1378,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 +@@ -2240,3 +2320,102 @@ mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) { #endif /* GSSAPI */ @@ -1426,10 +1481,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 d4d631ddc..2c64f07dc 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 +1500,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 08dc29e12..fb44ae733 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -578,7 +578,7 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, */ int @@ -1456,7 +1513,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 +@@ -594,7 +594,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 +1523,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 +@@ -627,6 +628,22 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, return 0; } @@ -1489,7 +1546,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 +@@ -1043,11 +1060,12 @@ mm_audit_event(struct ssh *ssh, ssh_audit_event_t event) sshbuf_free(m); } @@ -1502,10 +1559,10 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c int r; + int handle; - debug3("%s entering command %s", __func__, command); + debug3_f("entering command %s", command); -@@ -935,6 +953,30 @@ mm_audit_run_command(const char *command - fatal("%s: buffer error: %s", __func__, ssh_err(r)); +@@ -1057,6 +1075,30 @@ mm_audit_run_command(const char *command) + fatal_fr(r, "buffer error"); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m); @@ -1535,10 +1592,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 +@@ -1305,3 +1347,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 +1676,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 12c489c33..1bcbfd305 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -62,7 +62,9 @@ int mm_user_key_allowed(struct ssh *ssh, struct passwd *, struct sshkey *, int, struct sshauthopt **); int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *, const char *, struct sshkey *); @@ -1632,8 +1690,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); +@@ -89,7 +91,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,10 +1705,11 @@ 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 -@@ -81,6 +81,7 @@ +diff --git a/packet.c b/packet.c +index 5dd8269c2..bc22b8625 100644 +--- a/packet.c ++++ b/packet.c +@@ -77,6 +77,7 @@ #endif #include "xmalloc.h" @@ -1658,7 +1717,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 +@@ -513,6 +514,13 @@ ssh_packet_get_connection_out(struct ssh *ssh) return ssh->state->connection_out; } @@ -1672,10 +1731,10 @@ 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 - { +@@ -683,22 +691,19 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) struct session_state *state = ssh->state; u_int mode; + struct packet *p; + u_int had_keys = packet_state_has_keys(state); if (!state->initialized) @@ -1697,10 +1756,10 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c + state->outgoing_packet = NULL; sshbuf_free(state->incoming_packet); + state->incoming_packet = NULL; - 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 + while ((p = TAILQ_FIRST(&state->outgoing))) { + sshbuf_free(p->payload); + TAILQ_REMOVE(&state->outgoing, p, next); +@@ -739,8 +744,18 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) #endif /* WITH_ZLIB */ cipher_free(state->send_context); cipher_free(state->receive_context); @@ -1719,7 +1778,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 +@@ -1004,6 +1019,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 +1786,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) +@@ -2345,6 +2361,72 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1800,28 +1859,29 @@ 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 072f27425..e087d4c8a 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 d034f5c65..107edcf91 100644 +--- a/session.c ++++ b/session.c +@@ -139,6 +139,7 @@ static int session_pty_req(struct ssh *, Session *); + extern ServerOptions options; + extern char *__progname; 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, +@@ -617,6 +618,14 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); @@ -1835,35 +1895,34 @@ 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 + session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1); +@@ -707,15 +716,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 +@@ -1495,7 +1508,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) +@@ -1710,6 +1727,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 +@@ -1788,6 +1808,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 +@@ -2405,6 +2438,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 * +@@ -2418,6 +2477,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 +@@ -2494,14 +2557,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 +@@ -2627,6 +2690,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 +@@ -2690,7 +2762,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 344a1ddf9..a41c6efcd 100644 +--- a/session.h ++++ b/session.h @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2017,48 +2077,61 @@ 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 d6bece941..e49e4fb51 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -188,8 +188,8 @@ struct include_list includes = TAILQ_HEAD_INITIALIZER(includes); + struct sshbuf *loginmsg; /* 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 +@@ -202,6 +202,35 @@ 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; ++ } ++#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 +@@ -230,18 +259,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 +2139,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 +2161,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 +2172,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) +@@ -250,20 +301,38 @@ destroy_sensitive_data(void) /* Demote private to public keys for network child */ void @@ -2144,43 +2212,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 +@@ -441,7 +510,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) set_log_handler(mm_log_handler, pmonitor); /* Demote the private keys to public keys. */ @@ -2189,48 +2221,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) +@@ -1365,6 +1434,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) +@@ -1410,6 +1482,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 +2243,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) - } - } +@@ -1426,7 +1506,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 3ab81e268..ed7faf96d 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -213,6 +213,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) +@@ -958,6 +967,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ /* destroy_sensitive_data(ssh, 0); FIXME */ + close_listen_socks(); + if (options.pid_file != NULL) + unlink(options.pid_file); +-- +2.52.0 + diff --git a/openssh-7.1p2-audit-race-condition.patch b/0036-openssh-7.1p2-audit-race-condition.patch similarity index 70% rename from openssh-7.1p2-audit-race-condition.patch rename to 0036-openssh-7.1p2-audit-race-condition.patch index b5895f7..863f700 100644 --- a/openssh-7.1p2-audit-race-condition.patch +++ b/0036-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 ffa3fdb2ad2c7afc91993d9301e35d2e9a83ea47 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 36/53] openssh-7.1p2-audit-race-condition + +--- + monitor_wrap.c | 46 +++++++++++++++++++++++++++++++++++++ + monitor_wrap.h | 2 ++ + session.c | 61 ++++++++++++++++++++++++++++++++++++++++++++------ + 3 files changed, 102 insertions(+), 7 deletions(-) + +diff --git a/monitor_wrap.c b/monitor_wrap.c +index fb44ae733..17a6c9786 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -1426,4 +1426,50 @@ mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_ 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 1bcbfd305..2b814dbd1 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -97,6 +97,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 107edcf91..80282dfd8 100644 +--- a/session.c ++++ b/session.c +@@ -161,6 +161,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) +@@ -358,6 +362,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 +@@ -481,6 +487,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 +@@ -595,6 +603,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) +@@ -729,6 +740,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) +@@ -744,6 +757,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) +@@ -1490,6 +1517,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 +@@ -1507,13 +1561,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.52.0 + diff --git a/0037-openssh-9.0p1-audit-log.patch b/0037-openssh-9.0p1-audit-log.patch new file mode 100644 index 0000000..c58a5fe --- /dev/null +++ b/0037-openssh-9.0p1-audit-log.patch @@ -0,0 +1,265 @@ +From ef05b1fceddc64cfc7eb40daac60a137634d0a9f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 37/53] openssh-9.0p1-audit-log + +--- + audit-bsm.c | 2 +- + audit-linux.c | 76 +++++++++++++++++++++++++++++++++++++++++++-------- + audit.c | 18 +++++++++--- + audit.h | 2 +- + 4 files changed, 81 insertions(+), 17 deletions(-) + +diff --git a/audit-bsm.c b/audit-bsm.c +index a6292cb8f..0f2ef8235 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li) + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + /* not implemented */ + } +diff --git a/audit-linux.c b/audit-linux.c +index 4d3e9d41e..d2bc0b526 100644 +--- a/audit-linux.c ++++ b/audit-linux.c +@@ -52,7 +52,7 @@ extern u_int utmp_len; + const char *audit_username(void); + + static void +-linux_audit_user_logxxx(int uid, const char *username, ++linux_audit_user_logxxx(int uid, const char *username, const char *hostname, + const char *ip, const char *ttyn, int success, int event) + { + int audit_fd, rc, saved_errno; +@@ -68,7 +68,7 @@ linux_audit_user_logxxx(int uid, const char *username, + hostname = NULL; + rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", +- username == NULL ? uid : -1, NULL, ip, ttyn, success); ++ username == NULL ? uid : -1, hostname, ip, ttyn, success); + saved_errno = errno; + close(audit_fd); + +@@ -139,10 +139,12 @@ fatal_report: + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + char buf[AUDIT_LOG_SIZE]; + int audit_fd, rc, saved_errno; ++ const char *rip; ++ u_int i; + + audit_fd = audit_open(); + if (audit_fd < 0) { +@@ -152,14 +154,44 @@ audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) + else + return 0; /* Must prevent login */ + } ++ rip = ssh_remote_ipaddr(ssh); + snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, +- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); ++ buf, audit_username(), -1, NULL, rip, NULL, rv); + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) + goto out; +- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); ++ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp); + rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, +- ssh_remote_ipaddr(ssh), NULL, rv); ++ rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ if (cert) { ++ char *pbuf; ++ ++ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"", ++ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) { ++ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "principal %s", pbuf); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ } ++ } + out: + saved_errno = errno; + audit_close(audit_fd); +@@ -181,26 +213,34 @@ audit_connection_from(const char *host, int port) + int + audit_run_command(struct ssh *ssh, const char *command) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; + if (!user_login_count++) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_START); ++ free(audit_hostname); + return 0; + } + + void + audit_end_command(struct ssh *ssh, int handle, const char *command) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGOUT); ++ free(audit_hostname); + } + + void +@@ -213,31 +253,41 @@ void + audit_session_open(struct logininfo *li) + { + if (!user_login_count++) +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_LOGIN); +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_START); + } + + void + audit_session_close(struct logininfo *li) + { +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_LOGOUT); + } + + void + audit_event(struct ssh *ssh, ssh_audit_event_t event) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; ++ + switch(event) { + case SSH_NOLOGIN: + case SSH_LOGIN_ROOT_DENIED: + linux_audit_user_auth(-1, audit_username(), + ssh_remote_ipaddr(ssh), "ssh", 0, event); +- linux_audit_user_logxxx(-1, audit_username(), ++ linux_audit_user_logxxx(-1, audit_username(), audit_hostname, + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + case SSH_AUTH_FAIL_PASSWD: +@@ -257,9 +307,11 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + if (user_login_count) { + while (user_login_count--) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_END); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGOUT); + } +@@ -268,12 +320,14 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + case SSH_CONNECTION_ABANDON: + case SSH_INVALID_USER: + linux_audit_user_logxxx(-1, audit_username(), ++ audit_hostname, + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + default: + debug_f("unhandled event %d", event); + break; + } ++ free(audit_hostname); + } + + void +diff --git a/audit.c b/audit.c +index d0433c3a0..28d51a146 100644 +--- a/audit.c ++++ b/audit.c +@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev) + void + audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) + { +- char *fp; ++ char *key_fp = NULL; ++ char *issuer_fp = NULL; ++ struct sshkey_cert *cert = NULL; + +- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); +- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) ++ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) { ++ cert = key->cert; ++ issuer_fp = sshkey_fingerprint(cert->signature_key, ++ options.fingerprint_hash, SSH_FP_DEFAULT); ++ } ++ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0) + *rv = -SSH_ERR_INTERNAL_ERROR; +- free(fp); ++ if (key_fp) ++ free(key_fp); ++ if (issuer_fp) ++ free(issuer_fp); + } + + void +diff --git a/audit.h b/audit.h +index 45d66ccff..05ac132cf 100644 +--- a/audit.h ++++ b/audit.h +@@ -64,7 +64,7 @@ void audit_session_close(struct logininfo *); + int audit_run_command(struct ssh *, const char *); + void audit_end_command(struct ssh *, int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); +-int audit_keyusage(struct ssh *, int, char *, int); ++int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int); + void audit_key(struct ssh *, int, int *, const struct sshkey *); + void audit_unsupported(struct ssh *, int); + void audit_kex(struct ssh *, int, char *, char *, char *, char *); +-- +2.52.0 + diff --git a/openssh-7.7p1-fips.patch b/0038-openssh-7.7p1-fips.patch similarity index 59% rename from openssh-7.7p1-fips.patch rename to 0038-openssh-7.7p1-fips.patch index 5351571..18ebed3 100644 --- a/openssh-7.7p1-fips.patch +++ b/0038-openssh-7.7p1-fips.patch @@ -1,6 +1,33 @@ -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 d7dd45f9e19a71269828bc5f8567613a02f6feef Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 28 Aug 2025 14:01:38 +0200 +Subject: [PATCH 38/53] openssh-7.7p1-fips + +--- + dh.c | 41 ++++++++++++++++++++++ + dh.h | 1 + + kex-names.c | 6 +++- + kex.c | 3 +- + kexgen.c | 74 ++++++++++++++++++++++++++++++++-------- + kexgexc.c | 5 +++ + myproposal.h | 33 ++++++++++++++++++ + readconf.c | 16 ++++++--- + sandbox-seccomp-filter.c | 3 ++ + servconf.c | 18 +++++++--- + ssh-ed25519.c | 9 +++++ + ssh-gss.h | 5 +++ + ssh-keygen.c | 20 +++++++++-- + ssh-rsa.c | 3 ++ + ssh.c | 5 +++ + sshconnect2.c | 9 ++++- + sshd.c | 13 +++++++ + sshkey.c | 37 ++++++++++++++++++++ + 18 files changed, 271 insertions(+), 30 deletions(-) + +diff --git a/dh.c b/dh.c +index 168dea1dd..8c9a29fa7 100644 +--- a/dh.c ++++ b/dh.c @@ -36,6 +36,7 @@ #include @@ -9,7 +36,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 +49,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 +88,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 +100,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 31e395aa2..1360a4095 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 + +@@ -208,7 +209,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 +124,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 44f350ce8..da2a537ce 100644 +--- a/kex.c ++++ b/kex.c +@@ -38,6 +38,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + # ifdef HAVE_EVP_KDF_CTX_NEW + # include + # include +@@ -107,7 +108,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX], + + /* Append EXT_INFO signalling to KexAlgorithms */ + if (kexalgos == NULL) +- kexalgos = defprop[PROPOSAL_KEX_ALGS]; ++ kexalgos = FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : defprop[PROPOSAL_KEX_ALGS]; + if ((cp = kex_names_cat(kexalgos, ssh->kex->server ? + "ext-info-s,kex-strict-s-v00@openssh.com" : + "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) +diff --git a/kexgen.c b/kexgen.c +index 58edc79ad..9a970adf1 100644 +--- a/kexgen.c ++++ b/kexgen.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh) + break; + #endif /* WITH_OPENSSL */ + case KEX_C25519_SHA256: +- r = kex_c25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_keypair(kex); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_keypair(kex); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_keypair(kex); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) + break; + #endif /* WITH_OPENSSL */ + case KEX_C25519_SHA256: +- r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) + break; + #endif /* WITH_OPENSSL */ + case KEX_C25519_SHA256: +- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, ++ &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +diff --git a/kexgexc.c b/kexgexc.c +index 097d83f30..ccbb9b580 100644 +--- a/kexgexc.c ++++ b/kexgexc.c @@ -28,6 +28,7 @@ #ifdef WITH_OPENSSL @@ -105,8 +274,8 @@ diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c +#include #include - #include -@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32 + #include "openbsd-compat/openssl-compat.h" +@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh) r = SSH_ERR_ALLOC_FAIL; goto out; } @@ -117,10 +286,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 +308,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,9 +337,10 @@ 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 +diff --git a/readconf.c b/readconf.c +index 3f67f4de4..b6ad47b49 100644 +--- a/readconf.c ++++ b/readconf.c @@ -39,6 +39,7 @@ #include #include @@ -178,7 +349,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) +@@ -3078,11 +3079,16 @@ fill_default_options(Options * options) all_key = sshkey_alg_list(0, 0, 1, ','); all_sig = sshkey_alg_list(0, 1, 1, ','); /* remove unsupported algos from default lists */ @@ -200,10 +371,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 e0f2d4289..c52f64897 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -258,6 +258,9 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_open SC_DENY(__NR_open, EACCES), #endif @@ -213,18 +385,22 @@ 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 ac84b74d9..f78615c28 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -37,7 +37,10 @@ #include #include #include +#include - #ifdef HAVE_UTIL_H ++#ifdef HAVE_UTIL_H #include - #endif -@@ -226,11 +226,16 @@ assemble_algorithms(ServerOptions *o) ++#endif + #ifdef USE_SYSTEM_GLOB + # include + #else +@@ -244,11 +247,16 @@ assemble_algorithms(ServerOptions *o) all_key = sshkey_alg_list(0, 0, 1, ','); all_sig = sshkey_alg_list(0, 1, 1, ','); /* remove unsupported algos from default lists */ @@ -246,10 +422,150 @@ 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 c8caa2221..4bcd9ef81 100644 +--- a/ssh-ed25519.c ++++ b/ssh-ed25519.c +@@ -24,6 +24,7 @@ + + #include + #include ++#include + + #include "log.h" + #include "sshbuf.h" +@@ -163,6 +164,10 @@ ssh_ed25519_sign(struct sshkey *key, + key->ed25519_sk == NULL || + datalen >= INT_MAX - crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode()) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + smlen = slen = datalen + crypto_sign_ed25519_BYTES; + if ((sig = malloc(slen)) == NULL) + return SSH_ERR_ALLOC_FAIL; +@@ -244,6 +249,10 @@ ssh_ed25519_verify(const struct sshkey *key, + dlen >= INT_MAX - crypto_sign_ed25519_BYTES || + sig == NULL || siglen == 0) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode()) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + + if ((b = sshbuf_from(sig, siglen)) == NULL) + return SSH_ERR_ALLOC_FAIL; +diff --git a/ssh-gss.h b/ssh-gss.h +index a894e23c9..329dc9da0 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -88,6 +88,11 @@ extern char **k5users_allowed_cmds; + KEX_GSS_GRP14_SHA1_ID "," \ + KEX_GSS_GEX_SHA1_ID + ++#define GSS_KEX_DEFAULT_KEX_FIPS \ ++ KEX_GSS_GRP14_SHA256_ID "," \ ++ KEX_GSS_GRP16_SHA512_ID "," \ ++ KEX_GSS_NISTP256_SHA256_ID ++ + #include "digest.h" /* SSH_DIGEST_MAX_LENGTH */ + + typedef struct { +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 3c582a83a..afa279097 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -22,6 +22,7 @@ + #include "openbsd-compat/openssl-compat.h" + #include + #include ++#include + #include + #endif + +@@ -68,6 +69,7 @@ + #endif + + #define DEFAULT_KEY_TYPE_NAME "ed25519" ++#define FIPS_DEFAULT_KEY_TYPE_NAME "rsa" + + /* + * Default number of bits in the RSA and ECDSA keys. These value can be +@@ -195,6 +197,10 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) + #endif + } + #ifdef WITH_OPENSSL ++ if (FIPS_mode()) { ++ if (type == KEY_ED25519 || type == KEY_ED25519_SK) ++ fatal("ED25519 keys are not allowed in FIPS mode"); ++ } + switch (type) { + case KEY_RSA: + if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) +@@ -248,7 +254,7 @@ ask_filename(struct passwd *pw, const char *prompt) + char *name = NULL; + + if (key_type_name == NULL) +- name = _PATH_SSH_CLIENT_ID_ED25519; ++ name = FIPS_mode() ? _PATH_SSH_CLIENT_ID_RSA : _PATH_SSH_CLIENT_ID_ED25519; + else { + switch (sshkey_type_from_shortname(key_type_name)) { + #ifdef OPENSSL_HAS_ECC +@@ -1057,9 +1063,17 @@ do_gen_all_hostkeys(struct passwd *pw) + first = 1; + printf("%s: generating new host keys: ", __progname); + } ++ type = sshkey_type_from_shortname(key_types[i].key_type); ++ ++ /* Skip the keys that are not supported in FIPS mode */ ++ if (FIPS_mode() && type == KEY_ED25519) { ++ logit("Skipping %s key in FIPS mode", ++ key_types[i].key_type_display); ++ goto next; ++ } ++ + printf("%s ", key_types[i].key_type_display); + fflush(stdout); +- type = sshkey_type_from_shortname(key_types[i].key_type); + if ((fd = mkstemp(prv_tmp)) == -1) { + error("Could not save your private key in %s: %s", + prv_tmp, strerror(errno)); +@@ -3757,7 +3771,7 @@ main(int argc, char **argv) + } + + if (key_type_name == NULL) +- key_type_name = DEFAULT_KEY_TYPE_NAME; ++ key_type_name = FIPS_mode() ? FIPS_DEFAULT_KEY_TYPE_NAME : DEFAULT_KEY_TYPE_NAME; + + type = sshkey_type_from_shortname(key_type_name); + type_bits_valid(type, key_type_name, &bits); +diff --git a/ssh-rsa.c b/ssh-rsa.c +index fe1518984..9428df8d1 100644 +--- a/ssh-rsa.c ++++ b/ssh-rsa.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -142,6 +143,8 @@ ssh_rsa_generate(struct sshkey *k, int bits) + goto out; + } + if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) { ++ if (FIPS_mode()) ++ logit_f("the key length might be unsupported by FIPS mode approved key generation method"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +diff --git a/ssh.c b/ssh.c +index 8d27f6379..7d6ba516e 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -74,6 +74,7 @@ #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) +@@ -1664,6 +1665,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 b253f991b..fffa66c8d 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c @@ -45,6 +45,8 @@ #include #endif @@ -280,95 +597,48 @@ 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 + + gss = ssh_gssapi_client_mechanisms(gss_host, +- options.gss_client_identity, options.gss_kex_algorithms); ++ options.gss_client_identity, gss_kex_filtered); ++ free(gss_kex_filtered); ++ + if (gss) { + debug("Offering GSSAPI proposal: %s", gss); + xasprintf(&myproposal[PROPOSAL_KEX_ALGS], +diff --git a/sshd.c b/sshd.c +index ed7faf96d..de2baa5e4 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -44,6 +44,7 @@ + #include #include #include +#include #include + #include #include - #include -@@ -77,6 +78,7 @@ - #include - #include +@@ -55,6 +56,7 @@ + #ifdef WITH_OPENSSL + #include #include +#include #include "openbsd-compat/openssl-compat.h" #endif -@@ -1931,6 +1931,13 @@ main(int ac, char **av) +@@ -1613,6 +1615,13 @@ main(int ac, char **av) &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) do_log2_r(r, ll, "Unable to load host key \"%s\"", options.host_key_files[i]); @@ -382,7 +652,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) +@@ -1836,6 +1845,10 @@ main(int ac, char **av) /* Reinitialize the log (because of the fork above). */ log_init(__progname, options.log_level, options.log_facility, log_stderr); @@ -393,45 +663,27 @@ 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 +diff --git a/sshkey.c b/sshkey.c +index 148fee2b7..394d9b105 100644 +--- a/sshkey.c ++++ b/sshkey.c @@ -36,6 +36,7 @@ + #include + #include #include - #include - #include +#include #endif #include "crypto_api.h" -@@ -57,6 +58,7 @@ +@@ -58,6 +59,7 @@ #define SSHKEY_INTERNAL #include "sshkey.h" #include "match.h" +#include "log.h" #include "ssh-sk.h" + #include "ssh-pkcs11.h" - #ifdef WITH_XMSS -@@ -285,6 +285,18 @@ sshkey_alg_list(int certs_only, int plai +@@ -386,6 +388,18 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) impl = keyimpls[i]; if (impl->name == NULL || impl->type == KEY_NULL) continue; @@ -450,7 +702,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 +@@ -1418,6 +1432,20 @@ sshkey_read(struct sshkey *ret, char **cpp) return SSH_ERR_EC_CURVE_MISMATCH; } @@ -471,208 +723,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, +@@ -2251,6 +2279,11 @@ sshkey_sign(struct sshkey *key, *lenp = 0; if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ /* Fallthrough */ ++ if (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, +@@ -2290,6 +2323,10 @@ sshkey_verify(const struct sshkey *key, *detailsp = NULL; if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } - if ((impl = sshkey_impl_from_key(key)) == NULL) - return SSH_ERR_KEY_TYPE_UNKNOWN; - return impl->funcs->verify(key, sig, siglen, data, dlen, -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.52.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/0039-openssh-8.7p1-ssh-manpage.patch b/0039-openssh-8.7p1-ssh-manpage.patch new file mode 100644 index 0000000..d0e984d --- /dev/null +++ b/0039-openssh-8.7p1-ssh-manpage.patch @@ -0,0 +1,47 @@ +From 7167a191776dacf7e31cf8a8a2ed89887e49f4ee Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 39/53] openssh-8.7p1-ssh-manpage + +--- + ssh.1 | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ssh.1 b/ssh.1 +index 6a9fbdc5b..755cdef2b 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -510,12 +510,12 @@ For full details of the options listed below, and their possible values, see + .It BatchMode + .It BindAddress + .It BindInterface +-.It CASignatureAlgorithms + .It CanonicalDomains + .It CanonicalizeFallbackLocal + .It CanonicalizeHostname + .It CanonicalizeMaxDots + .It CanonicalizePermittedCNAMEs ++.It CASignatureAlgorithms + .It CertificateFile + .It ChannelTimeout + .It CheckHostIP +@@ -528,6 +528,7 @@ For full details of the options listed below, and their possible values, see + .It ControlPath + .It ControlPersist + .It DynamicForward ++.It EnableSSHKeysign + .It EnableEscapeCommandline + .It EnableSSHKeysign + .It EscapeChar +@@ -588,6 +589,8 @@ For full details of the options listed below, and their possible values, see + .It RemoteCommand + .It RemoteForward + .It RequestTTY ++.It RevokedHostKeys ++.It SecurityKeyProvider + .It RequiredRSASize + .It RevokedHostKeys + .It SecurityKeyProvider +-- +2.52.0 + diff --git a/openssh-8.7p1-negotiate-supported-algs.patch b/0040-openssh-8.7p1-negotiate-supported-algs.patch similarity index 69% rename from openssh-8.7p1-negotiate-supported-algs.patch rename to 0040-openssh-8.7p1-negotiate-supported-algs.patch index ee3637f..29f8213 100644 --- a/openssh-8.7p1-negotiate-supported-algs.patch +++ b/0040-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 53e44bd1f669ecd6a7429e94b55beec8e3c0c529 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 40/53] openssh-8.7p1-negotiate-supported-algs + +--- + regress/hostkey-agent.sh | 32 +++++++++++++++++++++++++------- + sshconnect2.c | 17 +++++++++++++++-- + 2 files changed, 40 insertions(+), 9 deletions(-) + +diff --git a/regress/hostkey-agent.sh b/regress/hostkey-agent.sh +index 28dcfe170..b9e716dcd 100644 +--- a/regress/hostkey-agent.sh ++++ b/regress/hostkey-agent.sh @@ -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 fffa66c8d..f43c81ad9 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, 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.52.0 + diff --git a/0041-openssh-9.0p1-evp-fips-kex.patch b/0041-openssh-9.0p1-evp-fips-kex.patch new file mode 100644 index 0000000..24ef8e8 --- /dev/null +++ b/0041-openssh-9.0p1-evp-fips-kex.patch @@ -0,0 +1,616 @@ +From 1c0d3b6e9868ef31b97be1679389e3db2616eccd Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 41/53] openssh-9.0p1-evp-fips-kex + +--- + dh.c | 98 +++++++++++++++++++++++++++++++++----- + kex.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + kex.h | 6 +++ + kexdh.c | 52 ++++++++++++++++++-- + kexecdh.c | 129 ++++++++++++++++++++++++++++++++++++++++---------- + 5 files changed, 382 insertions(+), 42 deletions(-) + +diff --git a/dh.c b/dh.c +index 8c9a29fa7..ea0a0b093 100644 +--- a/dh.c ++++ b/dh.c +@@ -37,6 +37,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "dh.h" + #include "pathnames.h" +@@ -290,10 +293,15 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) + int + dh_gen_key(DH *dh, int need) + { +- int pbits; +- const BIGNUM *dh_p, *pub_key; ++ const BIGNUM *dh_p, *dh_g; ++ BIGNUM *pub_key = NULL, *priv_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ int pbits, r = 0; + +- DH_get0_pqg(dh, &dh_p, NULL, NULL); ++ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); + + if (need < 0 || dh_p == NULL || + (pbits = BN_num_bits(dh_p)) <= 0 || +@@ -301,19 +309,85 @@ dh_gen_key(DH *dh, int need) + return SSH_ERR_INVALID_ARGUMENT; + if (need < 256) + need = 256; ++ ++ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { ++ OSSL_PARAM_BLD_free(param_bld); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ if (OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { ++ error_f("Could not set p,q,g parameters"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + /* + * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), + * so double requested need here. + */ +- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) +- return SSH_ERR_LIBCRYPTO_ERROR; +- +- if (DH_generate_key(dh) == 0) +- return SSH_ERR_LIBCRYPTO_ERROR; +- DH_get0_key(dh, &pub_key, NULL); +- if (!dh_pub_is_valid(dh, pub_key)) +- return SSH_ERR_INVALID_FORMAT; +- return 0; ++ if (OSSL_PARAM_BLD_push_int(param_bld, ++ OSSL_PKEY_PARAM_DH_PRIV_LEN, ++ MINIMUM(need * 2, pbits - 1)) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata(ctx, &pkey, ++ EVP_PKEY_KEY_PARAMETERS, params) != 1) { ++ error_f("Failed key generation"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* reuse context for key generation */ ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_keygen_init(ctx) != 1) { ++ error_f("Could not create or init context"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_generate(ctx, &pkey) != 1) { ++ error_f("Could not generate keys"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_public_check(ctx) != 1) { ++ error_f("The public key is incorrect"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, ++ &pub_key) != 1 || ++ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, ++ &priv_key) != 1 || ++ DH_set0_key(dh, pub_key, priv_key) != 1) { ++ error_f("Could not set pub/priv keys to DH struct"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* transferred */ ++ pub_key = NULL; ++ priv_key = NULL; ++out: ++ OSSL_PARAM_free(params); ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ BN_clear_free(pub_key); ++ BN_clear_free(priv_key); ++ return r; + } + + DH * +diff --git a/kex.c b/kex.c +index da2a537ce..56c80395c 100644 +--- a/kex.c ++++ b/kex.c +@@ -1613,3 +1613,142 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, + return r; + } + ++#ifdef WITH_OPENSSL ++/* ++ * Creates an EVP_PKEY from the given parameters and keys. ++ * The private key can be omitted. ++ */ ++EVP_PKEY * ++sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) ++{ ++ EVP_PKEY *ret = NULL; ++ OSSL_PARAM *params = NULL; ++ if (param_bld == NULL || ctx == NULL) { ++ debug2_f("param_bld or ctx is NULL"); ++ return NULL; ++ } ++ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ debug2_f("Could not build param list"); ++ return NULL; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { ++ debug2_f("EVP_PKEY_fromdata failed"); ++ OSSL_PARAM_free(params); ++ return NULL; ++ } ++ return ret; ++} ++ ++int ++kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ BN_CTX *bn_ctx = NULL; ++ uint8_t *pub_ser = NULL; ++ const char *group_name; ++ const EC_POINT *pub = NULL; ++ const BIGNUM *priv = NULL; ++ int ret = 0; ++ ++ if (k == NULL) ++ return SSH_ERR_INVALID_ARGUMENT; ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (bn_ctx = BN_CTX_new()) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, ++ group_name, ++ strlen(group_name)) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { ++ const EC_GROUP *group; ++ size_t len; ++ ++ group = EC_KEY_get0_group(k); ++ len = EC_POINT_point2oct(group, pub, ++ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); ++ if ((pub_ser = malloc(len)) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ EC_POINT_point2oct(group, ++ pub, ++ POINT_CONVERSION_UNCOMPRESSED, ++ pub_ser, ++ len, ++ bn_ctx); ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, ++ pub_ser, ++ len) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ } ++ if ((priv = EC_KEY_get0_private_key(k)) != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ BN_CTX_free(bn_ctx); ++ free(pub_ser); ++ return ret; ++} ++ ++int ++kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, ++ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = 0; ++ ++ /* create EVP_PKEY-DH key */ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { ++ error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { ++ error_f("Failed pushing params to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (priv != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ error_f("Failed pushing private key to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ return r; ++} ++#endif /* WITH_OPENSSL */ +diff --git a/kex.h b/kex.h +index cb06e85a3..6daafb159 100644 +--- a/kex.h ++++ b/kex.h +@@ -37,6 +37,9 @@ + # include + # include + # include ++# include ++# include ++# include + # ifdef OPENSSL_HAS_ECC + # include + # else /* OPENSSL_HAS_ECC */ +@@ -316,6 +319,9 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], + const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); ++int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, ++ const BIGNUM *, const BIGNUM *, const BIGNUM *); ++int kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey); + + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void dump_digest(const char *, const u_char *, int); +diff --git a/kexdh.c b/kexdh.c +index 6d5a7813d..b05277aa1 100644 +--- a/kexdh.c ++++ b/kexdh.c +@@ -36,6 +36,10 @@ + #include "openbsd-compat/openssl-compat.h" + #include + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -84,9 +88,12 @@ int + kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) + { + BIGNUM *shared_secret = NULL; ++ const BIGNUM *pub, *priv, *p, *q, *g; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; + u_char *kbuf = NULL; + size_t klen = 0; +- int kout, r; ++ int r = 0; + + #ifdef DEBUG_KEXDH + fprintf(stderr, "dh_pub= "); +@@ -101,24 +108,59 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) + r = SSH_ERR_MESSAGE_INCOMPLETE; + goto out; + } +- klen = DH_size(kex->dh); ++ ++ DH_get0_key(kex->dh, &pub, &priv); ++ DH_get0_pqg(kex->dh, &p, &q, &g); ++ /* import key */ ++ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); ++ if (r != 0) { ++ error_f("Could not create EVP_PKEY for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ /* import peer key ++ * the parameters should be the same as with pkey ++ */ ++ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); ++ if (r != 0) { ++ error_f("Could not import peer key for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { ++ error_f("Could not init EVP_PKEY_CTX for dh"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Could not get key size"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + if ((kbuf = malloc(klen)) == NULL || + (shared_secret = BN_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || +- BN_bin2bn(kbuf, kout, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || ++ BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ error_f("Could not derive key"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXDH +- dump_digest("shared secret", kbuf, kout); ++ dump_digest("shared secret", kbuf, klen); + #endif + r = sshbuf_put_bignum2(out, shared_secret); + out: + freezero(kbuf, klen); + BN_clear_free(shared_secret); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ EVP_PKEY_CTX_free(ctx); + return r; + } + +diff --git a/kexecdh.c b/kexecdh.c +index 500ec5725..1a1bae35e 100644 +--- a/kexecdh.c ++++ b/kexecdh.c +@@ -36,17 +36,57 @@ + + #include + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" + #include "sshbuf.h" + #include "digest.h" + #include "ssherr.h" ++#include "log.h" + + static int + kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, + const EC_GROUP *, struct sshbuf **); + ++static EC_KEY * ++generate_ec_keys(int ec_nid) ++{ ++ EC_KEY *client_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ const char *group_name; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) ++ goto out; ++ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Could not create OSSL_PARAM"); ++ goto out; ++ } ++ if (EVP_PKEY_keygen_init(ctx) != 1 || ++ EVP_PKEY_CTX_set_params(ctx, params) != 1 || ++ EVP_PKEY_generate(ctx, &pkey) != 1 || ++ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { ++ error_f("Could not generate ec keys"); ++ goto out; ++ } ++out: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); ++ return client_key; ++} ++ + int + kex_ecdh_keypair(struct kex *kex) + { +@@ -56,11 +96,7 @@ kex_ecdh_keypair(struct kex *kex) + struct sshbuf *buf = NULL; + int r; + +- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(client_key) != 1) { ++ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -102,11 +138,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, + *server_blobp = NULL; + *shared_secretp = NULL; + +- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(server_key) != 1) { ++ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -141,11 +173,21 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, + { + struct sshbuf *buf = NULL; + BIGNUM *shared_secret = NULL; +- EC_POINT *dh_pub = NULL; +- u_char *kbuf = NULL; +- size_t klen = 0; ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ u_char *kbuf = NULL, *pub = NULL; ++ size_t klen = 0, publen; ++ const char *group_name; + int r; + ++ /* import EC_KEY to EVP_PKEY */ ++ if ((r = kex_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { ++ error_f("Could not create EVP_PKEY"); ++ goto out; ++ } ++ + *shared_secretp = NULL; + + if ((buf = sshbuf_new()) == NULL) { +@@ -154,45 +196,82 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, + } + if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) + goto out; +- if ((dh_pub = EC_POINT_new(group)) == NULL) { ++ ++ /* the public key is in the buffer in octet string UNCOMPRESSED ++ * format. See sshbuf_put_ec */ ++ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) ++ goto out; ++ sshbuf_reset(buf); ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { ++ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Failed to set params for dh_pkey"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &dh_pkey, ++ EVP_PKEY_PUBLIC_KEY, params) != 1 || ++ EVP_PKEY_public_check(ctx) != 1) { ++ error_f("Peer public key import failed"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- sshbuf_reset(buf); + + #ifdef DEBUG_KEXECDH + fputs("public key:\n", stderr); +- sshkey_dump_ec_point(group, dh_pub); ++ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); + #endif +- if (sshkey_ec_validate_public(group, dh_pub) != 0) { +- r = SSH_ERR_MESSAGE_INCOMPLETE; ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Failed to get derive information"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- klen = (EC_GROUP_get_degree(group) + 7) / 8; +- if ((kbuf = malloc(klen)) == NULL || +- (shared_secret = BN_new()) == NULL) { ++ if ((kbuf = malloc(klen)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || +- BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXECDH + dump_digest("shared secret", kbuf, klen); + #endif ++ if ((shared_secret = BN_new()) == NULL || ++ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } + if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) + goto out; + *shared_secretp = buf; + buf = NULL; + out: +- EC_POINT_clear_free(dh_pub); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); + BN_clear_free(shared_secret); + freezero(kbuf, klen); ++ freezero(pub, publen); + sshbuf_free(buf); + return r; + } +-- +2.52.0 + diff --git a/0042-openssh-8.7p1-nohostsha1proof.patch b/0042-openssh-8.7p1-nohostsha1proof.patch new file mode 100644 index 0000000..681d051 --- /dev/null +++ b/0042-openssh-8.7p1-nohostsha1proof.patch @@ -0,0 +1,332 @@ +From 1cd47036353899fe066f5241d3d70778f103c0e0 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 42/53] openssh-8.7p1-nohostsha1proof + +--- + compat.c | 6 ++++++ + compat.h | 2 +- + monitor.c | 27 +++++++++++++++++------ + regress/unittests/kex/test_kex.c | 3 ++- + regress/unittests/sshkey/test_file.c | 3 ++- + regress/unittests/sshkey/test_fuzz.c | 3 ++- + regress/unittests/sshkey/test_sshkey.c | 30 ++++++++++++++++---------- + serverloop.c | 6 +++++- + ssh-rsa.c | 3 ++- + sshconnect2.c | 8 +++++++ + sshd-session.c | 21 ++++++++++++++++++ + 11 files changed, 88 insertions(+), 24 deletions(-) + +diff --git a/compat.c b/compat.c +index b59f0bfc0..4e611dc39 100644 +--- a/compat.c ++++ b/compat.c +@@ -42,6 +42,7 @@ void + compat_banner(struct ssh *ssh, const char *version) + { + int i; ++ int forbid_ssh_rsa = 0; + static struct { + char *pat; + int bugs; +@@ -125,16 +126,21 @@ compat_banner(struct ssh *ssh, const char *version) + }; + + /* process table, return first match */ ++ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA); + ssh->compat = 0; + for (i = 0; check[i].pat; i++) { + if (match_pattern_list(version, check[i].pat, 0) == 1) { + debug_f("match: %s pat %s compat 0x%08x", + version, check[i].pat, check[i].bugs); + ssh->compat = check[i].bugs; ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + return; + } + } + debug_f("no match: %s", version); ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + } + + /* Always returns pointer to allocated memory, caller must free. */ +diff --git a/compat.h b/compat.h +index 1a19060fc..2e6db5bf9 100644 +--- a/compat.h ++++ b/compat.h +@@ -30,7 +30,7 @@ + #define SSH_BUG_UTF8TTYMODE 0x00000001 + #define SSH_BUG_SIGTYPE 0x00000002 + #define SSH_BUG_SIGTYPE74 0x00000004 +-/* #define unused 0x00000008 */ ++#define SSH_RH_RSASIGSHA 0x00000008 + #define SSH_OLD_SESSIONID 0x00000010 + /* #define unused 0x00000020 */ + #define SSH_BUG_DEBUG 0x00000040 +diff --git a/monitor.c b/monitor.c +index b2f501790..6c83739ee 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -754,11 +754,12 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) + struct sshkey *pubkey, *key; + struct sshbuf *sigbuf = NULL; + u_char *p = NULL, *signature = NULL; +- char *alg = NULL; +- size_t datlen, siglen; +- int r, is_proof = 0, keyid; +- u_int compat; ++ char *alg = NULL, *effective_alg; ++ size_t datlen, siglen, alglen; ++ int r, is_proof = 0; ++ u_int keyid, compat; + const char proof_req[] = "hostkeys-prove-00@openssh.com"; ++ const char safe_rsa[] = "rsa-sha2-256"; + + debug3_f("entering"); + +@@ -816,18 +817,30 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) + } + + if ((key = get_hostkey_by_index(keyid)) != NULL) { +- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } ++ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg, + options.sk_provider, NULL, compat)) != 0) + fatal_fr(r, "sign"); + } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && + auth_sock > 0) { ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } + if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, +- p, datlen, alg, compat)) != 0) ++ p, datlen, effective_alg, compat)) != 0) + fatal_fr(r, "agent sign"); + } else + fatal_f("no hostkey from index %d", keyid); + +- debug3_f("%s %s signature len=%zu", alg, ++ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg, + is_proof ? "hostkey proof" : "KEX", siglen); + + sshbuf_reset(m); +diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c +index 16c2f2dff..f4700deeb 100644 +--- a/regress/unittests/kex/test_kex.c ++++ b/regress/unittests/kex/test_kex.c +@@ -110,7 +110,8 @@ do_kex_with_key(char *kex, char *cipher, char *mac, + kex_params.proposal[PROPOSAL_MAC_ALGS_CTOS] = mac; + kex_params.proposal[PROPOSAL_MAC_ALGS_STOC] = mac; + } +- keyname = strdup(sshkey_ssh_name(private)); ++ keyname = (strcmp(sshkey_ssh_name(private), "ssh-rsa")) ? ++ strdup(sshkey_ssh_name(private)) : strdup("rsa-sha2-256"); + ASSERT_PTR_NE(keyname, NULL); + kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; + ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); +diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c +index e412b75d8..5b06bc905 100644 +--- a/regress/unittests/sshkey/test_file.c ++++ b/regress/unittests/sshkey/test_file.c +@@ -106,6 +106,7 @@ sshkey_file_tests(void) + sshkey_free(k2); + TEST_DONE(); + ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("load RSA cert with SHA1 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0); + ASSERT_PTR_NE(k2, NULL); +@@ -113,7 +114,7 @@ sshkey_file_tests(void) + ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); + ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa"); + sshkey_free(k2); +- TEST_DONE(); ++ TEST_DONE(); */ + + TEST_START("load RSA cert with SHA512 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0); +diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c +index d0f47d7cf..ba4d506d5 100644 +--- a/regress/unittests/sshkey/test_fuzz.c ++++ b/regress/unittests/sshkey/test_fuzz.c +@@ -273,13 +273,14 @@ sshkey_fuzz_tests(void) + TEST_DONE(); + + #ifdef WITH_OPENSSL ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("fuzz RSA sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "ssh-rsa"); + sshkey_free(k1); +- TEST_DONE(); ++ TEST_DONE();*/ + + TEST_START("fuzz RSA SHA256 sig"); + buf = load_file("rsa_1"); +diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c +index d0c46a90b..7b5e51b83 100644 +--- a/regress/unittests/sshkey/test_sshkey.c ++++ b/regress/unittests/sshkey/test_sshkey.c +@@ -59,6 +59,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, + u_char *sigblob; + size_t siglen; + ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ ++ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; ++ + ca_buf = sshbuf_new(); + ASSERT_PTR_NE(ca_buf, NULL); + ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); +@@ -100,8 +103,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, + ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ + ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ + ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, +- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0); +- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ ++ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected); ++ if (expected == 0) ++ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ + + free(sigblob); + sshbuf_free(ca_buf); +@@ -118,16 +122,20 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, + { + size_t len; + u_char *sig; ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT crypto policies */ ++ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0) : 0; + + ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, +- NULL, NULL, 0), 0); +- ASSERT_SIZE_T_GT(len, 8); +- ASSERT_PTR_NE(sig, NULL); +- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); +- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); +- /* Fuzz test is more comprehensive, this is just a smoke test */ +- sig[len - 5] ^= 0x10; +- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ NULL, NULL, 0), expected); ++ if (expected == 0) { ++ ASSERT_SIZE_T_GT(len, 8); ++ ASSERT_PTR_NE(sig, NULL); ++ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); ++ /* Fuzz test is more comprehensive, this is just a smoke test */ ++ sig[len - 5] ^= 0x10; ++ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ } + free(sig); + } + +@@ -552,7 +560,7 @@ sshkey_tests(void) + ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, + NULL), 0); + k3 = get_private("rsa_1"); +- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); ++ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256"); + ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), + SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); + ASSERT_PTR_EQ(k4, NULL); +diff --git a/serverloop.c b/serverloop.c +index 5d3b194d1..55411a6b4 100644 +--- a/serverloop.c ++++ b/serverloop.c +@@ -76,6 +76,7 @@ + #include "auth-options.h" + #include "serverloop.h" + #include "ssherr.h" ++#include "compat.h" + + extern ServerOptions options; + +@@ -721,7 +722,10 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) + else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) + sigalg = "rsa-sha2-256"; + } +- ++ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) { ++ sigalg = "rsa-sha2-512"; ++ debug3_f("SHA1 signature is not supported, falling back to %s", sigalg); ++ } + debug3_f("sign %s key (index %d) using sigalg %s", + sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); + if ((r = sshbuf_put_cstring(sigbuf, +diff --git a/ssh-rsa.c b/ssh-rsa.c +index 9428df8d1..7843f3e26 100644 +--- a/ssh-rsa.c ++++ b/ssh-rsa.c +@@ -533,7 +533,8 @@ ssh_rsa_verify(const struct sshkey *key, + ret = SSH_ERR_INVALID_ARGUMENT; + goto out; + } +- if (hash_alg != want_alg) { ++ if (hash_alg != want_alg && want_alg != SSH_DIGEST_SHA1) { ++ debug_f("Unexpected digest algorithm: got %d, wanted %d", hash_alg, want_alg); + ret = SSH_ERR_SIGNATURE_INVALID; + goto out; + } +diff --git a/sshconnect2.c b/sshconnect2.c +index f43c81ad9..2d98fc3da 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -1434,6 +1434,14 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, + retried = 1; + goto retry_pin; + } ++ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) { ++ char rsa_safe_alg[] = "rsa-sha2-512"; ++ debug3_f("trying to fallback to algorithm %s", rsa_safe_alg); ++ ++ if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, ++ rsa_safe_alg, options.sk_provider, pin, compat)) != 0) ++ debug_fr(r, "sshkey_sign - RSA fallback"); ++ } + goto out; + } + +diff --git a/sshd-session.c b/sshd-session.c +index e49e4fb51..a558bbc33 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1288,6 +1288,27 @@ main(int ac, char **av) + + check_ip_options(ssh); + ++ { ++ struct sshkey *rsakey = NULL; ++ rsakey = get_hostkey_private_by_type(KEY_RSA, 0, ssh); ++ if (rsakey == NULL) ++ rsakey = get_hostkey_private_by_type(KEY_RSA_CERT, 0, ssh); ++ ++ if (rsakey != NULL) { ++ size_t sign_size = 0; ++ u_char *tmp = NULL; ++ u_char data[] = "Test SHA1 vector"; ++ int res; ++ ++ res = sshkey_sign(rsakey, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); ++ free(tmp); ++ if (res == SSH_ERR_LIBCRYPTO_ERROR) { ++ verbose_f("SHA1 in signatures is disabled for RSA keys"); ++ ssh->compat |= SSH_RH_RSASIGSHA; ++ } ++ } ++ } ++ + /* Prepare the channels layer */ + channel_init_channels(ssh); + channel_set_af(ssh, options.address_family); +-- +2.52.0 + diff --git a/0043-openssh-9.9p1-separate-keysign.patch b/0043-openssh-9.9p1-separate-keysign.patch new file mode 100644 index 0000000..60a6d4f --- /dev/null +++ b/0043-openssh-9.9p1-separate-keysign.patch @@ -0,0 +1,25 @@ +From 1799ea7ad21a579b864a536709d732f4a8e533dc Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 43/53] openssh-9.9p1-separate-keysign + +--- + ssh_config.5 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ssh_config.5 b/ssh_config.5 +index 8ac5e1633..a06fbfa11 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -797,7 +797,7 @@ or + This option should be placed in the non-hostspecific section. + See + .Xr ssh-keysign 8 +-for more information. ++for more information. ssh-keysign should be installed explicitly. + .It Cm EscapeChar + Sets the escape character (default: + .Ql ~ ) . +-- +2.52.0 + diff --git a/0044-openssh-9.9p1-openssl-mlkem.patch b/0044-openssh-9.9p1-openssl-mlkem.patch new file mode 100644 index 0000000..3e72647 --- /dev/null +++ b/0044-openssh-9.9p1-openssl-mlkem.patch @@ -0,0 +1,402 @@ +From 21202362f4ddaeb630d873fb426039004ac82338 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 44/53] openssh-9.9p1-openssl-mlkem + +--- + kex-names.c | 23 +++- + kexmlkem768x25519.c | 291 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 313 insertions(+), 1 deletion(-) + +diff --git a/kex-names.c b/kex-names.c +index 1360a4095..9c96e5cb0 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -109,6 +109,19 @@ static const struct kexalg gss_kexalgs[] = { + { NULL, 0, -1, -1, 0}, + }; + ++static int is_mlkem768_available() ++{ ++ static int is_fetched = -1; ++ ++ if (is_fetched == -1) { ++ EVP_KEM *mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = mlkem768 != NULL ? 1 : 0; ++ EVP_KEM_free(mlkem768); ++ } ++ ++ return is_fetched; ++} ++ + static char * + kex_alg_list_internal(char sep, const struct kexalg *algs) + { +@@ -116,8 +129,12 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) + const struct kexalg *k; + char sep_str[2] = {sep, '\0'}; + +- for (k = kexalgs; k->name != NULL; k++) ++ for (k = kexalgs; k->name != NULL; k++) { ++ if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ continue; + xextendf(&ret, sep_str, "%s", k->name); ++ } + + return ret; + } +@@ -139,6 +156,10 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + ++ if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ return NULL; ++ + for (k = kexalgs; k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index 2585d1db3..ab6167221 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -44,10 +44,127 @@ + #ifdef USE_MLKEM768X25519 + + #include "libcrux_mlkem768_sha3.h" ++#include ++#include ++#include ++ ++static int ++mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++{ ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL; ++ int ret = SSH_ERR_INTERNAL_ERROR; ++ size_t pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES, privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES; ++ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL); ++ if (ctx == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_keygen_init(ctx) <= 0 ++ || EVP_PKEY_keygen(ctx, &pkey) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &pubkey_size) <= 0 ++ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &privkey_size) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES ++ || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ret = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (ret == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ return ret; ++} ++ ++static int ++mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL, ++ pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES ++ || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} ++ ++static int ++mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t wrappedlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL, ++ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} + + int + kex_kem_mlkem768x25519_keypair(struct kex *kex) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char rnd[LIBCRUX_ML_KEM_KEY_PAIR_PRNG_LEN], *cp = NULL; + size_t need; +@@ -82,6 +199,36 @@ kex_kem_mlkem768x25519_keypair(struct kex *kex) + explicit_bzero(rnd, sizeof(rnd)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ u_char *cp = NULL; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++ if ((buf = sshbuf_new()) == NULL) ++ return SSH_ERR_ALLOC_FAIL; ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if ((r = sshbuf_reserve(buf, need, &cp)) != 0) ++ goto out; ++ if ((r = mlkem768_keypair_gen(cp, kex->mlkem768_client_key)) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", cp, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++#endif ++ cp += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ kexc25519_keygen(kex->c25519_client_key, cp); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key c25519:", cp, CURVE25519_SIZE); ++#endif ++ /* success */ ++ r = 0; ++ kex->client_pub = buf; ++ buf = NULL; ++ out: ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int +@@ -89,6 +236,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *server_blob = NULL; + struct sshbuf *buf = NULL; + const u_char *client_pub; +@@ -181,12 +329,97 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + sshbuf_free(server_blob); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *server_blob = NULL; ++ struct sshbuf *buf = NULL; ++ const u_char *client_pub; ++ u_char server_pub[CURVE25519_SIZE], server_key[CURVE25519_SIZE]; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ struct libcrux_mlkem768_enc_result enc; /* FIXME */ ++ ++ *server_blobp = NULL; ++ *shared_secretp = NULL; ++ ++ /* client_blob contains both KEM and ECDH client pubkeys */ ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(client_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ client_pub = sshbuf_ptr(client_blob); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", client_pub, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++ dump_digest("client public key 25519:", ++ client_pub + crypto_kem_mlkem768_PUBLICKEYBYTES, ++ CURVE25519_SIZE); ++#endif ++ ++ /* allocate buffer for concatenation of KEM key and ECDH shared key */ ++ /* the buffer will be hashed and the result is the shared secret */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ /* allocate space for encrypted KEM key and ECDH pub key */ ++ if ((server_blob = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (mlkem768_encap_secret(client_pub, enc.snd, enc.fst.value) != 0) ++ goto out; ++ ++ /* generate ECDH key pair, store server pubkey after ciphertext */ ++ kexc25519_keygen(server_key, server_pub); ++ if ((r = sshbuf_put(buf, enc.snd, sizeof(enc.snd))) != 0 || ++ (r = sshbuf_put(server_blob, enc.fst.value, sizeof(enc.fst.value))) != 0 || ++ (r = sshbuf_put(server_blob, server_pub, sizeof(server_pub))) != 0) ++ goto out; ++ /* append ECDH shared key */ ++ client_pub += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE); ++ dump_digest("server cipher text:", ++ enc.fst.value, sizeof(enc.fst.value)); ++ dump_digest("server kem key:", enc.snd, sizeof(enc.snd)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* string-encoded hash is resulting shared secret */ ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *server_blobp = server_blob; ++ *shared_secretp = buf; ++ server_blob = NULL; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(server_key, sizeof(server_key)); ++ explicit_bzero(&enc, sizeof(enc)); ++ sshbuf_free(server_blob); ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int + kex_kem_mlkem768x25519_dec(struct kex *kex, + const struct sshbuf *server_blob, struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char mlkem_key[crypto_kem_mlkem768_BYTES]; + const u_char *ciphertext, *server_pub; +@@ -254,6 +487,64 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, + explicit_bzero(mlkem_key, sizeof(mlkem_key)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ const u_char *ciphertext, *server_pub; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ u_char decap[crypto_kem_mlkem768_BYTES]; ++ size_t need; ++ int r; ++ ++ *shared_secretp = NULL; ++ ++ need = crypto_kem_mlkem768_CIPHERTEXTBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(server_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ ciphertext = sshbuf_ptr(server_blob); ++ server_pub = ciphertext + crypto_kem_mlkem768_CIPHERTEXTBYTES; ++ /* hash concatenation of KEM key and ECDH shared key */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++#ifdef DEBUG_KEXECDH ++ dump_digest("server cipher text:", ciphertext, crypto_kem_mlkem768_CIPHERTEXTBYTES); ++ dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE); ++#endif ++ if ((r = mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap)) != 0) ++ goto out; ++ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0) ++ goto out; ++ if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub, ++ buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, ++ hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client kem key:", decap, sizeof(decap)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *shared_secretp = buf; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(decap, sizeof(decap)); ++ sshbuf_free(buf); ++ return r; ++#endif + } + #else /* USE_MLKEM768X25519 */ + int +-- +2.52.0 + diff --git a/0045-openssh-9.9p2-error_processing.patch b/0045-openssh-9.9p2-error_processing.patch new file mode 100644 index 0000000..48aa76a --- /dev/null +++ b/0045-openssh-9.9p2-error_processing.patch @@ -0,0 +1,25 @@ +From edbbdc306c1710dae777ef315a0d2c5f43134d33 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Fri, 16 May 2025 14:53:54 +0200 +Subject: [PATCH 45/53] openssh-9.9p2-error_processing + +--- + ssh-agent.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ssh-agent.c b/ssh-agent.c +index df241379c..dc246066d 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1346,6 +1346,8 @@ process_add_identity(SocketEntry *e) + if ((r = sshkey_private_deserialize(e->request, &k)) != 0 || + k == NULL || + (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) { ++ if (!r) /* k == NULL */ ++ r = SSH_ERR_INTERNAL_ERROR; + error_fr(r, "parse"); + goto out; + } +-- +2.52.0 + diff --git a/0046-Provide-better-error-for-non-supported-private-keys.patch b/0046-Provide-better-error-for-non-supported-private-keys.patch new file mode 100644 index 0000000..dd30967 --- /dev/null +++ b/0046-Provide-better-error-for-non-supported-private-keys.patch @@ -0,0 +1,27 @@ +From 0772377e00b13f5afaa1b146ce32d0218e9f0d24 Mon Sep 17 00:00:00 2001 +From: Zoltan Fridrich +Date: Wed, 16 Apr 2025 15:11:59 +0200 +Subject: [PATCH 46/53] Provide better error for non-supported private keys + +Signed-off-by: Zoltan Fridrich +--- + sshkey.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sshkey.c b/sshkey.c +index 394d9b105..eba55ef92 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -3539,6 +3539,9 @@ translate_libcrypto_error(unsigned long pem_err) + return SSH_ERR_LIBCRYPTO_ERROR; + } + case ERR_LIB_ASN1: ++#ifdef ERR_LIB_OSSL_DECODER ++ case ERR_LIB_OSSL_DECODER: ++#endif + return SSH_ERR_INVALID_FORMAT; + } + return SSH_ERR_LIBCRYPTO_ERROR; +-- +2.52.0 + diff --git a/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch b/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch new file mode 100644 index 0000000..3bfab92 --- /dev/null +++ b/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch @@ -0,0 +1,86 @@ +From d458a65ccac2283563c0fc0962519bb5a9bbd315 Mon Sep 17 00:00:00 2001 +From: Zoltan Fridrich +Date: Mon, 5 May 2025 11:52:25 +0200 +Subject: [PATCH 47/53] Ignore bad hostkeys in known_hosts file + +Signed-off-by: Zoltan Fridrich +--- + hostfile.c | 15 +++++++++++++++ + hostfile.h | 1 + + ssh.c | 2 ++ + 3 files changed, 18 insertions(+) + +diff --git a/hostfile.c b/hostfile.c +index 4cec57da5..652d15762 100644 +--- a/hostfile.c ++++ b/hostfile.c +@@ -63,6 +63,14 @@ + #include "hmac.h" + #include "sshbuf.h" + ++static int required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; ++ ++void ++hostfile_set_minimum_rsa_size(int size) ++{ ++ required_rsa_size = size; ++} ++ + /* XXX hmac is too easy to dictionary attack; use bcrypt? */ + + static int +@@ -233,6 +241,7 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx) + struct load_callback_ctx *ctx = (struct load_callback_ctx *)_ctx; + struct hostkeys *hostkeys = ctx->hostkeys; + struct hostkey_entry *tmp; ++ int r = 0; + + if (l->status == HKF_STATUS_INVALID) { + /* XXX make this verbose() in the future */ +@@ -241,6 +250,12 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx) + return 0; + } + ++ if ((r = sshkey_check_rsa_length(l->key, required_rsa_size)) != 0) { ++ debug2_f("%s:%ld: ignoring hostkey: %s", ++ l->path, l->linenum, ssh_err(r)); ++ return 0; ++ } ++ + debug3_f("found %skey type %s in file %s:%lu", + l->marker == MRK_NONE ? "" : + (l->marker == MRK_CA ? "ca " : "revoked "), +diff --git a/hostfile.h b/hostfile.h +index a24a4e329..0e9b1a19a 100644 +--- a/hostfile.h ++++ b/hostfile.h +@@ -119,5 +119,6 @@ int hostkeys_foreach_file(const char *path, FILE *f, + const char *host, const char *ip, u_int options, u_int note); + + void hostfile_create_user_ssh_dir(const char *, int); ++void hostfile_set_minimum_rsa_size(int); + + #endif +diff --git a/ssh.c b/ssh.c +index 7d6ba516e..320ac6834 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -106,6 +106,7 @@ + #include "ssherr.h" + #include "myproposal.h" + #include "utf8.h" ++#include "hostfile.h" + + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" +@@ -1409,6 +1410,7 @@ main(int ac, char **av) + options.update_hostkeys = 0; + } + } ++ hostfile_set_minimum_rsa_size(options.required_rsa_size); + if (options.connection_attempts <= 0) + fatal("Invalid number of ConnectionAttempts"); + +-- +2.52.0 + diff --git a/0048-support-authentication-indicators-in-GSSAPI.patch b/0048-support-authentication-indicators-in-GSSAPI.patch new file mode 100644 index 0000000..664a006 --- /dev/null +++ b/0048-support-authentication-indicators-in-GSSAPI.patch @@ -0,0 +1,450 @@ +From 1cf5e40e14d707de2318747758b012fc7245cb7b Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 10 Jun 2024 23:00:03 +0300 +Subject: [PATCH 48/53] support authentication indicators in GSSAPI + +RFC 6680 defines a set of GSSAPI extensions to handle attributes +associated with the GSSAPI names. MIT Kerberos and FreeIPA use +name attributes to add information about pre-authentication methods used +to acquire the initial Kerberos ticket. The attribute 'auth-indicators' +may contain list of strings that KDC has associated with the ticket +issuance process. + +Use authentication indicators to authorise or deny access to SSH server. +GSSAPIIndicators setting allows to specify a list of possible indicators +that a Kerberos ticket presented must or must not contain. More details +on the syntax are provided in sshd_config(5) man page. + +Fixes: https://bugzilla.mindrot.org/show_bug.cgi?id=2696 + +Signed-off-by: Alexander Bokovoy +--- + configure.ac | 1 + + gss-serv-krb5.c | 64 +++++++++++++++++++++++++++--- + gss-serv.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++- + servconf.c | 15 ++++++- + servconf.h | 2 + + ssh-gss.h | 7 ++++ + sshd_config.5 | 44 +++++++++++++++++++++ + 7 files changed, 228 insertions(+), 8 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 805be4b5e..9d3b19925 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -5050,6 +5050,7 @@ AC_ARG_WITH([kerberos5], + AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h]) + AC_CHECK_HEADERS([gssapi_krb5.h gssapi/gssapi_krb5.h]) + AC_CHECK_HEADERS([gssapi_generic.h gssapi/gssapi_generic.h]) ++ AC_CHECK_HEADERS([gssapi_ext.h gssapi/gssapi_ext.h]) + + AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1], + [Define this if you want to use libkafs' AFS support])]) +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 03188d9b3..2c786ef14 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -43,6 +43,7 @@ + #include "log.h" + #include "misc.h" + #include "servconf.h" ++#include "match.h" + + #include "ssh-gss.h" + +@@ -87,6 +88,32 @@ ssh_gssapi_krb5_init(void) + return 1; + } + ++/* Check if any of the indicators in the Kerberos ticket match ++ * one of indicators in the list of allowed/denied rules. ++ * In case of the match, apply the decision from the rule. ++ * In case of no indicator from the ticket matching the rule, deny ++ */ ++ ++static int ++ssh_gssapi_check_indicators(ssh_gssapi_client *client, int *matched) ++{ ++ int ret; ++ u_int i; ++ ++ /* Check indicators */ ++ for (i = 0; client->indicators[i] != NULL; i++) { ++ ret = match_pattern_list(client->indicators[i], ++ options.gss_indicators, 1); ++ /* negative or positive match */ ++ if (ret != 0) { ++ *matched = i; ++ return ret; ++ } ++ } ++ /* No rule matched */ ++ return 0; ++} ++ + /* Check if this user is OK to login. This only works with krb5 - other + * GSSAPI mechanisms will need their own. + * Returns true if the user is OK to log in, otherwise returns 0 +@@ -193,7 +220,7 @@ static int + ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + { + krb5_principal princ; +- int retval; ++ int retval, matched; + const char *errmsg; + int k5login_exists; + +@@ -216,17 +243,42 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + if (k5login_exists && + ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", +- name, (char *)client->displayname.value); ++ errmsg = "krb5_kuserok"; + } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value, + name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s " +- "(ssh_gssapi_krb5_cmdok)", +- name, (char *)client->displayname.value); ++ errmsg = "ssh_gssapi_krb5_cmdok"; + } else + retval = 0; + ++ if ((retval == 1) && (options.gss_indicators != NULL)) { ++ /* At this point the configuration enforces presence of indicators ++ * so we drop the authorization result again */ ++ retval = 0; ++ if (client->indicators) { ++ matched = -1; ++ retval = ssh_gssapi_check_indicators(client, &matched); ++ if (retval != 0) { ++ retval = (retval == 1); ++ logit("Ticket contains indicator %s, " ++ "krb5 principal %s is %s", ++ client->indicators[matched], ++ (char *)client->displayname.value, ++ retval ? "allowed" : "denied"); ++ goto cont; ++ } ++ } ++ if (retval == 0) { ++ logit("GSSAPI authentication indicators enforced " ++ "but not matched. krb5 principal %s denied", ++ (char *)client->displayname.value); ++ } ++ } ++cont: ++ if (retval == 1) { ++ logit("Authorized to %s, krb5 principal %s (%s)", ++ name, (char *)client->displayname.value, errmsg); ++ } + krb5_free_principal(krb_context, princ); + return retval; + } +diff --git a/gss-serv.c b/gss-serv.c +index d2bc03486..be80e17ca 100644 +--- a/gss-serv.c ++++ b/gss-serv.c +@@ -54,7 +54,7 @@ extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, +- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; ++ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0, NULL}; + + ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; +@@ -296,6 +296,92 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name) + return GSS_S_COMPLETE; + } + ++ ++/* Extract authentication indicators from the Kerberos ticket. Authentication ++ * indicators are GSSAPI name attributes for the name "auth-indicators". ++ * Multiple indicators might be present in the ticket. ++ * Each indicator is a utf8 string. */ ++ ++#define AUTH_INDICATORS_TAG "auth-indicators" ++ ++/* Privileged (called from accept_secure_ctx) */ ++static OM_uint32 ++ssh_gssapi_getindicators(Gssctxt *ctx, gss_name_t gss_name, ssh_gssapi_client *client) ++{ ++ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; ++ gss_buffer_desc value = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; ++ int is_mechname, authenticated, complete, more; ++ size_t count, i; ++ ++ ctx->major = gss_inquire_name(&ctx->minor, gss_name, ++ &is_mechname, NULL, &attrs); ++ if (ctx->major != GSS_S_COMPLETE) { ++ return (ctx->major); ++ } ++ ++ if (attrs == GSS_C_NO_BUFFER_SET) { ++ /* No indicators in the ticket */ ++ return (0); ++ } ++ ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ count++; ++ } ++ ++ if (count == 0) { ++ /* No auth-indicators in the ticket */ ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (0); ++ } ++ ++ client->indicators = recallocarray(NULL, 0, count + 1, sizeof(char*)); ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ authenticated = 0; ++ complete = 0; ++ more = -1; ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ /* retrieve all indicators */ ++ while (more != 0) { ++ value.value = NULL; ++ display_value.value = NULL; ++ ctx->major = gss_get_name_attribute(&ctx->minor, gss_name, ++ &attrs->elements[i], &authenticated, ++ &complete, &value, &display_value, &more); ++ if (ctx->major != GSS_S_COMPLETE) { ++ goto out; ++ } ++ ++ if ((value.value != NULL) && authenticated) { ++ client->indicators[count] = xmalloc(value.length + 1); ++ memcpy(client->indicators[count], value.value, value.length); ++ client->indicators[count][value.length] = '\0'; ++ count++; ++ } ++ } ++ } ++ ++out: ++ (void) gss_release_buffer(&ctx->minor, &value); ++ (void) gss_release_buffer(&ctx->minor, &display_value); ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (ctx->major); ++} ++ ++ + /* Extract the client details from a given context. This can only reliably + * be called once for a context */ + +@@ -385,6 +471,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + } + + gss_release_buffer(&ctx->minor, &ename); ++ /* Retrieve authentication indicators, if they exist */ ++ if ((ctx->major = ssh_gssapi_getindicators(ctx, ++ ctx->client, client))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } + + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; +@@ -447,6 +539,7 @@ int + ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + { + OM_uint32 lmin; ++ size_t i; + + (void) kex; /* used in privilege separation */ + +@@ -465,6 +558,14 @@ ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); + gss_release_cred(&lmin, &gssapi_client.creds); ++ ++ if (gssapi_client.indicators != NULL) { ++ for(i = 0; gssapi_client.indicators[i] != NULL; i++) { ++ free(gssapi_client.indicators[i]); ++ } ++ free(gssapi_client.indicators); ++ } ++ + explicit_bzero(&gssapi_client, + sizeof(ssh_gssapi_client)); + return 0; +diff --git a/servconf.c b/servconf.c +index f78615c28..e53e8ea30 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -146,6 +146,7 @@ initialize_server_options(ServerOptions *options) + options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; ++ options->gss_indicators = NULL; + options->use_kuserok = -1; + options->enable_k5users = -1; + options->password_authentication = -1; +@@ -591,7 +592,7 @@ typedef enum { + sPerSourcePenalties, sPerSourcePenaltyExemptList, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, +- sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, ++ sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, +@@ -687,6 +688,7 @@ static struct { + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, + { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, ++ { "gssapiindicators", sGssIndicators, SSHCFG_ALL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, +@@ -696,6 +698,7 @@ static struct { + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, + { "gssapienablek5users", sUnsupported, SSHCFG_ALL }, ++ { "gssapiindicators", sUnsupported, SSHCFG_ALL }, + #endif + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, +@@ -1722,6 +1725,15 @@ process_server_config_line_depth(ServerOptions *options, char *line, + options->gss_kex_algorithms = xstrdup(arg); + break; + ++ case sGssIndicators: ++ arg = argv_next(&ac, &av); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: %s missing argument.", ++ filename, linenum, keyword); ++ if (options->gss_indicators == NULL) ++ options->gss_indicators = xstrdup(arg); ++ break; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -3344,6 +3356,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); ++ dump_cfg_string(sGssIndicators, o->gss_indicators); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, +diff --git a/servconf.h b/servconf.h +index c08cf6a7a..c7cec5ece 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -179,6 +179,7 @@ typedef struct { + char **allow_groups; + u_int num_deny_groups; + char **deny_groups; ++ char *gss_indicators; + + u_int num_subsystems; + char **subsystem_name; +@@ -308,6 +309,7 @@ TAILQ_HEAD(include_list, include_item); + M_CP_STROPT(routing_domain); \ + M_CP_STROPT(permit_user_env_allowlist); \ + M_CP_STROPT(pam_service_name); \ ++ M_CP_STROPT(gss_indicators); \ + M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ + M_CP_STRARRAYOPT(allow_users, num_allow_users); \ + M_CP_STRARRAYOPT(deny_users, num_deny_users); \ +diff --git a/ssh-gss.h b/ssh-gss.h +index 329dc9da0..1506719a9 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -34,6 +34,12 @@ + #include + #endif + ++#ifdef HAVE_GSSAPI_EXT_H ++#include ++#elif defined(HAVE_GSSAPI_GSSAPI_EXT_H) ++#include ++#endif ++ + #ifdef KRB5 + # ifndef HEIMDAL + # ifdef HAVE_GSSAPI_GENERIC_H +@@ -112,6 +118,7 @@ typedef struct { + ssh_gssapi_ccache store; + int used; + int updated; ++ char **indicators; /* auth indicators */ + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +diff --git a/sshd_config.5 b/sshd_config.5 +index c172d5aab..676d6d4d2 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -785,6 +785,50 @@ gss-nistp256-sha256- + gss-curve25519-sha256- + .Ed + This option only applies to connections using GSSAPI. ++.It Cm GSSAPIIndicators ++Specifies whether to accept or deny GSSAPI authenticated access if Kerberos ++mechanism is used and Kerberos ticket contains a particular set of ++authentication indicators. The values can be specified as a comma-separated list ++.Cm [!]name1,[!]name2,... . ++When indicator's name is prefixed with !, the authentication indicator 'name' ++will deny access to the system. Otherwise, one of non-negated authentication ++indicators must be present in the Kerberos ticket to allow access. If ++.Cm GSSAPIIndicators ++is defined, a Kerberos ticket that has indicators but does not match the ++policy will get denial. If at least one indicator is configured, whether for ++access or denial, tickets without authentication indicators will be explicitly ++rejected. ++.Pp ++By default systems using MIT Kerberos 1.17 or later will not assign any ++indicators. SPAKE and PKINIT methods add authentication indicators ++to all successful authentications. The SPAKE pre-authentication method is ++preferred over an encrypted timestamp pre-authentication when passwords used to ++authenticate user principals. Kerberos KDCs built with Heimdal Kerberos ++(including Samba AD DC built with Heimdal) do not add authentication ++indicators. However, OpenSSH built against Heimdal Kerberos library is able to ++inquire authentication indicators and thus can be used to check for their presence. ++.Pp ++Indicator name is case-sensitive and depends on the configuration of a ++particular Kerberos deployment. Indicators available in MIT Kerberos and ++FreeIPA environments: ++.Pp ++.Bl -tag -width XXXX -offset indent -compact ++.It Cm hardened ++SPAKE or encrypted timestamp pre-authentication mechanisms in MIT Kerberos and FreeIPA ++.It Cm pkinit ++smartcard or PKCS11 token-based pre-authentication in MIT Kerberos and FreeIPA ++.It Cm radius ++pre-authentication based on a RADIUS server in MIT Kerberos and FreeIPA ++.It Cm otp ++TOTP/HOTP-based two-factor pre-authentication in FreeIPA ++.It Cm idp ++OAuth2-based pre-authentication in FreeIPA using an external identity provider ++and device authorization grant flow ++.It Cm passkey ++FIDO2-based pre-authentication in FreeIPA, using FIDO2 USB and NFC tokens ++.El ++.Pp ++The default is to not use GSSAPI authentication indicators for access decisions. + .It Cm HostbasedAcceptedAlgorithms + The default is handled system-wide by + .Xr crypto-policies 7 . +-- +2.52.0 + diff --git a/0049-NIST-curves-hybrid-KEX-implementation.patch b/0049-NIST-curves-hybrid-KEX-implementation.patch new file mode 100644 index 0000000..9ce23be --- /dev/null +++ b/0049-NIST-curves-hybrid-KEX-implementation.patch @@ -0,0 +1,1216 @@ +From 3642efdf9be4d377cfd802d6a33cb083f0d846b8 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Mon, 20 Oct 2025 16:07:31 +0200 +Subject: [PATCH 49/53] NIST curves hybrid KEX implementation + +--- + crypto_api.h | 4 + + kex-names.c | 78 +++- + kex.c | 1 + + kex.h | 19 + + kexgen.c | 56 ++- + kexmlkem768x25519.c | 678 +++++++++++++++++++++++++++++-- + monitor.c | 2 + + myproposal.h | 4 + + regress/unittests/kex/test_kex.c | 4 + + ssh-keyscan.c | 2 + + ssh_api.c | 4 + + sshconnect2.c | 2 + + sshd-auth.c | 2 + + 13 files changed, 819 insertions(+), 37 deletions(-) + +diff --git a/crypto_api.h b/crypto_api.h +index 693b67bbc..ec3d2f277 100644 +--- a/crypto_api.h ++++ b/crypto_api.h +@@ -56,4 +56,8 @@ int crypto_kem_sntrup761_keypair(unsigned char *pk, unsigned char *sk); + #define crypto_kem_mlkem768_CIPHERTEXTBYTES 1088 + #define crypto_kem_mlkem768_BYTES 32 + ++#define crypto_kem_mlkem1024_PUBLICKEYBYTES 1568 ++#define crypto_kem_mlkem1024_SECRETKEYBYTES 3168 ++#define crypto_kem_mlkem1024_CIPHERTEXTBYTES 1568 ++ + #endif /* crypto_api_h */ +diff --git a/kex-names.c b/kex-names.c +index 9c96e5cb0..ceecd9312 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -91,6 +91,10 @@ static const struct kexalg kexalgs[] = { + #ifdef USE_MLKEM768X25519 + { KEX_MLKEM768X25519_SHA256, KEX_KEM_MLKEM768X25519_SHA256, 0, + SSH_DIGEST_SHA256, KEX_IS_PQ }, ++ { KEX_MLKEM768NISTP256_SHA256, KEX_KEM_MLKEM768NISTP256_SHA256, 0, ++ SSH_DIGEST_SHA256, KEX_IS_PQ }, ++ { KEX_MLKEM1024NISTP384_SHA384, KEX_KEM_MLKEM1024NISTP384_SHA384, 0, ++ SSH_DIGEST_SHA384, KEX_IS_PQ }, + #endif + #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + { NULL, 0, -1, -1, 0 }, +@@ -109,13 +113,30 @@ static const struct kexalg gss_kexalgs[] = { + { NULL, 0, -1, -1, 0}, + }; + ++/* ++ * 0 - unavailable ++ * 1 - available in non-FIPS mode ++ * 2 - available in FIPS mode ++ */ + static int is_mlkem768_available() + { + static int is_fetched = -1; + + if (is_fetched == -1) { +- EVP_KEM *mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); +- is_fetched = mlkem768 != NULL ? 1 : 0; ++ EVP_KEM *mlkem768 = NULL; ++ ++ if (FIPS_mode() == 1) { ++ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = mlkem768 != NULL ? 2 : 0; ++ ++ if (is_fetched == 0) { ++ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips"); ++ is_fetched = mlkem768 != NULL ? 1 : 0; ++ } ++ } else { ++ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = mlkem768 != NULL ? 1 : 0; ++ } + EVP_KEM_free(mlkem768); + } + +@@ -128,11 +149,32 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) + char *ret = NULL; + const struct kexalg *k; + char sep_str[2] = {sep, '\0'}; ++ int x25519mlkem_available = 0, nistmlkem_available = 0; + +- for (k = kexalgs; k->name != NULL; k++) { +- if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 +- && !is_mlkem768_available()) ++ /* ++ * FIPS provider can provide ML-KEMs and then all hybrids are available ++ * Otherwise only NIST hybrids are available ++ * */ ++ if (FIPS_mode()) { ++ if (is_mlkem768_available() == 2) { ++ x25519mlkem_available = 1; ++ nistmlkem_available = 1; ++ } else if (is_mlkem768_available() == 1) { ++ nistmlkem_available = 1; ++ } ++ } else { ++ if (is_mlkem768_available() > 0) { ++ x25519mlkem_available = 1; ++ nistmlkem_available = 1; ++ } ++ } ++ ++ for (k = algs; k->name != NULL; k++) { ++ if ( (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 && x25519mlkem_available == 0) ++ || (strcmp(k->name, KEX_MLKEM768NISTP256_SHA256) == 0 && nistmlkem_available == 0) ++ || (strcmp(k->name, KEX_MLKEM1024NISTP384_SHA384) == 0 && nistmlkem_available == 0)) + continue; ++ + xextendf(&ret, sep_str, "%s", k->name); + } + +@@ -155,10 +197,30 @@ static const struct kexalg * + kex_alg_by_name(const char *name) + { + const struct kexalg *k; ++ int x25519mlkem_available = 0, nistmlkem_available = 0; + +- if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 +- && !is_mlkem768_available()) +- return NULL; ++ /* ++ * FIPS provider can provide ML-KEMs and then all hybrids are available ++ * Otherwise only NIST hybrids are available ++ * */ ++ if (FIPS_mode()) { ++ if (is_mlkem768_available() == 2) { ++ x25519mlkem_available = 1; ++ nistmlkem_available = 1; ++ } else if (is_mlkem768_available() == 1) { ++ nistmlkem_available = 1; ++ } ++ } else { ++ if (is_mlkem768_available() > 0) { ++ x25519mlkem_available = 1; ++ nistmlkem_available = 1; ++ } ++ } ++ ++ if ( (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 && x25519mlkem_available == 0) ++ || (strcmp(name, KEX_MLKEM768NISTP256_SHA256) == 0 && nistmlkem_available == 0) ++ || (strcmp(name, KEX_MLKEM1024NISTP384_SHA384) == 0 && nistmlkem_available == 0)) ++ return NULL; + + for (k = kexalgs; k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) +diff --git a/kex.c b/kex.c +index 56c80395c..7dd16ba2b 100644 +--- a/kex.c ++++ b/kex.c +@@ -751,6 +751,7 @@ kex_free(struct kex *kex) + #ifdef OPENSSL_HAS_ECC + EC_KEY_free(kex->ec_client_key); + #endif /* OPENSSL_HAS_ECC */ ++ EVP_PKEY_free(kex->ec_hybrid_client_key); + #endif /* WITH_OPENSSL */ + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(kex->newkeys[mode]); +diff --git a/kex.h b/kex.h +index 6daafb159..354f312e8 100644 +--- a/kex.h ++++ b/kex.h +@@ -72,6 +72,8 @@ + #define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512" + #define KEX_SNTRUP761X25519_SHA512_OLD "sntrup761x25519-sha512@openssh.com" + #define KEX_MLKEM768X25519_SHA256 "mlkem768x25519-sha256" ++#define KEX_MLKEM768NISTP256_SHA256 "mlkem768nistp256-sha256" ++#define KEX_MLKEM1024NISTP384_SHA384 "mlkem1024nistp384-sha384" + + #define COMP_NONE 0 + #define COMP_DELAYED 2 +@@ -110,6 +112,8 @@ enum kex_exchange { + KEX_C25519_SHA256, + KEX_KEM_SNTRUP761X25519_SHA512, + KEX_KEM_MLKEM768X25519_SHA256, ++ KEX_KEM_MLKEM768NISTP256_SHA256, ++ KEX_KEM_MLKEM1024NISTP384_SHA384, + #ifdef GSSAPI + KEX_GSS_GRP1_SHA1, + KEX_GSS_GRP14_SHA1, +@@ -210,6 +214,9 @@ struct kex { + u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */ + u_char mlkem768_client_key[crypto_kem_mlkem768_SECRETKEYBYTES]; /* KEM */ + struct sshbuf *client_pub; ++ /* FIXME */ ++ EVP_PKEY *ec_hybrid_client_key; /* NIST hybrids */ ++ u_char mlkem1024_client_key[crypto_kem_mlkem1024_SECRETKEYBYTES]; /* ML-KEM 1024 + NIST */ + }; + + int kex_name_valid(const char *); +@@ -292,6 +299,18 @@ int kex_kem_mlkem768x25519_enc(struct kex *, const struct sshbuf *, + int kex_kem_mlkem768x25519_dec(struct kex *, const struct sshbuf *, + struct sshbuf **); + ++int kex_kem_mlkem768nistp256_keypair(struct kex *); ++int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *, ++ struct sshbuf **, struct sshbuf **); ++int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *, ++ struct sshbuf **); ++ ++int kex_kem_mlkem1024nistp384_keypair(struct kex *); ++int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *, ++ struct sshbuf **, struct sshbuf **); ++int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *, ++ struct sshbuf **); ++ + int kex_dh_keygen(struct kex *); + int kex_dh_compute_key(struct kex *, BIGNUM *, struct sshbuf *); + +diff --git a/kexgen.c b/kexgen.c +index 9a970adf1..79faa0b3e 100644 +--- a/kexgen.c ++++ b/kexgen.c +@@ -133,12 +133,24 @@ kex_gen_client(struct ssh *ssh) + break; + case KEX_KEM_MLKEM768X25519_SHA256: + if (FIPS_mode()) { +- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); +- r = SSH_ERR_INVALID_ARGUMENT; ++ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ if (mlkem == NULL) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ EVP_KEM_free(mlkem); ++ r = kex_kem_mlkem768x25519_keypair(kex); ++ } + } else { + r = kex_kem_mlkem768x25519_keypair(kex); + } + break; ++ case KEX_KEM_MLKEM768NISTP256_SHA256: ++ r = kex_kem_mlkem768nistp256_keypair(kex); ++ break; ++ case KEX_KEM_MLKEM1024NISTP384_SHA384: ++ r = kex_kem_mlkem1024nistp384_keypair(kex); ++ break; + default: + r = SSH_ERR_INVALID_ARGUMENT; + break; +@@ -223,13 +235,28 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) + break; + case KEX_KEM_MLKEM768X25519_SHA256: + if (FIPS_mode()) { +- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); +- r = SSH_ERR_INVALID_ARGUMENT; ++ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ if (mlkem == NULL) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ EVP_KEM_free(mlkem); ++ r = kex_kem_mlkem768x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + } else { + r = kex_kem_mlkem768x25519_dec(kex, server_blob, + &shared_secret); + } + break; ++ case KEX_KEM_MLKEM768NISTP256_SHA256: ++ r = kex_kem_mlkem768nistp256_dec(kex, server_blob, ++ &shared_secret); ++ break; ++ case KEX_KEM_MLKEM1024NISTP384_SHA384: ++ r = kex_kem_mlkem1024nistp384_dec(kex, server_blob, ++ &shared_secret); ++ break; + default: + r = SSH_ERR_INVALID_ARGUMENT; + break; +@@ -283,6 +310,8 @@ out: + sizeof(kex->sntrup761_client_key)); + explicit_bzero(kex->mlkem768_client_key, + sizeof(kex->mlkem768_client_key)); ++ explicit_bzero(kex->mlkem1024_client_key, ++ sizeof(kex->mlkem1024_client_key)); + sshbuf_free(server_host_key_blob); + free(signature); + sshbuf_free(tmp); +@@ -362,13 +391,28 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) + break; + case KEX_KEM_MLKEM768X25519_SHA256: + if (FIPS_mode()) { +- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); +- r = SSH_ERR_INVALID_ARGUMENT; ++ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ if (mlkem == NULL) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ EVP_KEM_free(mlkem); ++ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + } else { + r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); + } + break; ++ case KEX_KEM_MLKEM768NISTP256_SHA256: ++ r = kex_kem_mlkem768nistp256_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ break; ++ case KEX_KEM_MLKEM1024NISTP384_SHA384: ++ r = kex_kem_mlkem1024nistp384_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ break; + default: + r = SSH_ERR_INVALID_ARGUMENT; + break; +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index ab6167221..c56d67ff4 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -44,19 +44,33 @@ + #ifdef USE_MLKEM768X25519 + + #include "libcrux_mlkem768_sha3.h" ++#include ++#include + #include + #include ++#include + #include + ++#define FIPS_FALLBACK_PROPQ "provider=default,-fips" ++ + static int +-mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++mlkem_keypair_gen(const char *algname, unsigned char *pubkeybuf, size_t pubkey_size, ++ unsigned char *privkeybuf, size_t privkey_size) + { + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + int ret = SSH_ERR_INTERNAL_ERROR; +- size_t pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES, privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES; ++ size_t got_pub_size = pubkey_size, got_priv_size = privkey_size; ++ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, algname, NULL); ++ ++ if (ctx == NULL && FIPS_mode()) { ++ /* We have filtered x25519 + ML-KEM in FIPS mode earlier ++ * so if we are in FIPS mode and ML-KEM is not available with default propq, ++ * we can fetch it from the default provider */ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, algname, FIPS_FALLBACK_PROPQ); ++ } + +- ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL); + if (ctx == NULL) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto err; +@@ -68,17 +82,23 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) + goto err; + } + +- if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &pubkey_size) <= 0 +- || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &privkey_size) <= 0) { ++ if (EVP_PKEY_get_raw_public_key(pkey, NULL, &got_pub_size) <= 0 ++ || EVP_PKEY_get_raw_private_key(pkey, NULL, &got_priv_size) <= 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto err; + } + +- if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES +- || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) { ++ if (privkey_size != got_priv_size || pubkey_size != got_pub_size) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto err; + } ++ ++ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &got_pub_size) <= 0 ++ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &got_priv_size) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ + ret = 0; + + err: +@@ -90,27 +110,57 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) + } + + static int +-mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++{ ++ return mlkem_keypair_gen("mlkem768", pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES, ++ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); ++} ++ ++static int ++mlkem1024_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++{ ++ return mlkem_keypair_gen("mlkem1024", pubkeybuf, crypto_kem_mlkem1024_PUBLICKEYBYTES, ++ privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES); ++} ++ ++static int ++mlkem_encap_secret(const char *mlkem_alg, const u_char *pubkeybuf, u_char *secret, u_char *out) + { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + int r = SSH_ERR_INTERNAL_ERROR; +- size_t outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, +- secretlen = crypto_kem_mlkem768_BYTES; ++ size_t outlen, expected_outlen, publen, secretlen = crypto_kem_mlkem768_BYTES; ++ int fips_fallback = 0; ++ ++ if (strcmp(mlkem_alg, "mlkem768") == 0) { ++ outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES; ++ publen = crypto_kem_mlkem768_PUBLICKEYBYTES; ++ } else if (strcmp(mlkem_alg, "mlkem1024") == 0) { ++ outlen = crypto_kem_mlkem1024_CIPHERTEXTBYTES; ++ publen = crypto_kem_mlkem1024_PUBLICKEYBYTES; ++ } else ++ return r; + +- pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL, +- pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES); ++ expected_outlen = outlen; ++ ++ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, mlkem_alg, NULL, ++ pubkeybuf, publen); ++ if (pkey == NULL && FIPS_mode()) { ++ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, mlkem_alg, FIPS_FALLBACK_PROPQ, ++ pubkeybuf, publen); ++ fips_fallback = 1; ++ } + if (pkey == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto err; + } + +- ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, fips_fallback ? FIPS_FALLBACK_PROPQ : NULL); + if (ctx == NULL + || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 +- || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0 ++ || EVP_PKEY_encapsulate(ctx, out, &expected_outlen, secret, &secretlen) <= 0 + || secretlen != crypto_kem_mlkem768_BYTES +- || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) { ++ || outlen != expected_outlen) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto err; + } +@@ -126,25 +176,45 @@ mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) + } + + static int +-mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++{ ++ return mlkem_encap_secret("mlkem768", pubkeybuf, secret, out); ++} ++ ++static int ++mlkem1024_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++{ ++ return mlkem_encap_secret("mlkem1024", pubkeybuf, secret, out); ++} ++ ++static int ++mlkem_decap_secret(const char *algname, ++ const u_char *privkeybuf, size_t privkey_len, ++ const u_char *wrapped, size_t wrapped_len, ++ u_char *secret) + { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + int r = SSH_ERR_INTERNAL_ERROR; +- size_t wrappedlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, +- secretlen = crypto_kem_mlkem768_BYTES; ++ size_t secretlen = crypto_kem_mlkem768_BYTES; ++ int fips_fallback = 0; + +- pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL, +- privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); ++ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, algname, ++ NULL, privkeybuf, privkey_len); ++ if (pkey == NULL && FIPS_mode()) { ++ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, algname, ++ FIPS_FALLBACK_PROPQ, privkeybuf, privkey_len); ++ fips_fallback = 1; ++ } + if (pkey == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto err; + } + +- ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, fips_fallback ? FIPS_FALLBACK_PROPQ : NULL); + if (ctx == NULL + || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 +- || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0 ++ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrapped_len) <= 0 + || secretlen != crypto_kem_mlkem768_BYTES) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto err; +@@ -161,6 +231,20 @@ mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *s + return r; + } + ++static int ++mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++{ ++ return mlkem_decap_secret("mlkem768", privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES, ++ wrapped, crypto_kem_mlkem768_CIPHERTEXTBYTES, secret); ++} ++ ++static int ++mlkem1024_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++{ ++ return mlkem_decap_secret("mlkem1024", privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES, ++ wrapped, crypto_kem_mlkem1024_CIPHERTEXTBYTES, secret); ++} ++ + int + kex_kem_mlkem768x25519_keypair(struct kex *kex) + { +@@ -337,7 +421,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + u_char hash[SSH_DIGEST_MAX_LENGTH]; + size_t need; + int r = SSH_ERR_INTERNAL_ERROR; +- struct libcrux_mlkem768_enc_result enc; /* FIXME */ ++ struct libcrux_mlkem768_enc_result enc; + + *server_blobp = NULL; + *shared_secretp = NULL; +@@ -546,6 +630,519 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, + return r; + #endif + } ++ ++#define NIST_P256_COMPRESSED_LEN 33 ++#define NIST_P256_UNCOMPRESSED_LEN 65 ++#define NIST_P384_COMPRESSED_LEN 49 ++#define NIST_P384_UNCOMPRESSED_LEN 97 ++#define NIST_BUF_MAX_SIZE NIST_P384_UNCOMPRESSED_LEN ++ ++static const char ec256[] = "P-256"; ++static const char ec384[] = "P-384"; ++static const char *len2curve_name(size_t len) ++{ ++ switch (len) { ++ case NIST_P256_COMPRESSED_LEN: ++ case NIST_P256_UNCOMPRESSED_LEN: ++ return ec256; ++ break; ++ case NIST_P384_COMPRESSED_LEN: ++ case NIST_P384_UNCOMPRESSED_LEN: ++ return ec384; ++ break; ++ } ++ return NULL; ++} ++ ++static EVP_PKEY * ++buf2nist_key(const unsigned char *pub_key_buf, size_t pub_key_len) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM params[3]; ++ const char *curve_name = len2curve_name(pub_key_len); ++ ++ if (curve_name == NULL) ++ return NULL; ++ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); ++ if (!ctx) ++ goto err; ++ ++ if (EVP_PKEY_fromdata_init(ctx) <= 0) ++ goto err; ++ ++ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0); ++ params[1] = OSSL_PARAM_construct_octet_string( ++ OSSL_PKEY_PARAM_PUB_KEY, (void *)pub_key_buf, pub_key_len); ++ params[2] = OSSL_PARAM_construct_end(); ++ ++ if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) ++ goto err; ++ ++ EVP_PKEY_CTX_free(ctx); ++ return pkey; ++ ++err: ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ return NULL; ++} ++ ++static int ++kex_nist_shared_key_ext(EVP_PKEY *priv_key, ++ const u_char *pub_key_buf, size_t pub_key_len, struct sshbuf *out) ++{ ++ EVP_PKEY_CTX *ctx = NULL; ++ unsigned char *shared_secret = NULL; ++ size_t shared_secret_len = 0; ++ EVP_PKEY *peer_key = buf2nist_key(pub_key_buf, pub_key_len); ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++ if (peer_key == NULL) ++ return SSH_ERR_KEY_LENGTH; ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, priv_key, NULL); ++ if (!ctx) ++ goto end; ++ ++ if ((EVP_PKEY_derive_init(ctx) <= 0) ++ || EVP_PKEY_derive_set_peer(ctx, peer_key) <= 0 ++ || EVP_PKEY_derive(ctx, NULL, &shared_secret_len) <= 0) ++ goto end; ++ ++ shared_secret = OPENSSL_malloc(shared_secret_len); ++ if (shared_secret == NULL) ++ goto end; ++ ++ if (EVP_PKEY_derive(ctx, shared_secret, &shared_secret_len) <= 0) ++ goto end; ++ ++ if ((r = sshbuf_put(out, shared_secret, shared_secret_len)) != 0) ++ goto end; ++ ++ r = 0; ++ ++end: ++ EVP_PKEY_free(peer_key); ++ if (shared_secret) ++ OPENSSL_clear_free(shared_secret, shared_secret_len); ++ EVP_PKEY_CTX_free(ctx); ++ ++ return r; ++} ++ ++static EVP_PKEY * ++nist_pkey_keygen(size_t pub_key_len) ++{ ++ const char *curve_name = len2curve_name(pub_key_len); ++ EVP_PKEY_CTX *pctx = NULL; ++ EVP_PKEY *pkey = NULL; ++ OSSL_PARAM params[2]; ++ ++ if (curve_name == NULL) ++ return NULL; ++ ++ pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); ++ if (!pctx) ++ return NULL; ++ ++ if (EVP_PKEY_keygen_init(pctx) <= 0) { ++ EVP_PKEY_CTX_free(pctx); ++ return NULL; ++ } ++ ++ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0); ++ params[1] = OSSL_PARAM_construct_end(); ++ ++ if (EVP_PKEY_CTX_set_params(pctx, params) <= 0 ++ || EVP_PKEY_keygen(pctx, &pkey) <= 0) { ++ EVP_PKEY_CTX_free(pctx); ++ return NULL; ++ } ++ ++ EVP_PKEY_CTX_free(pctx); ++ return pkey; ++} ++ ++static size_t decompress_pub_key(void *pub, size_t compressed_len, size_t decompressed_len) ++{ ++ EC_GROUP *group = NULL; ++ EC_POINT *point = NULL; ++ BN_CTX *ctx = NULL; ++ size_t len = 0; ++ int group_nid = NID_undef; ++ ++ switch (compressed_len) { ++ case NIST_P256_COMPRESSED_LEN: ++ group_nid = NID_X9_62_prime256v1; ++ break; ++ case NIST_P384_COMPRESSED_LEN: ++ group_nid = NID_secp384r1; ++ break; ++ default: ++ return 0; ++ break; ++ } ++ ++ ctx = BN_CTX_new(); ++ group = EC_GROUP_new_by_curve_name(group_nid); ++ if (ctx == NULL || group == NULL) ++ goto err; ++ ++ point = EC_POINT_new(group); ++ if (point == NULL) ++ goto err; ++ ++ if (!EC_POINT_oct2point(group, point, pub, compressed_len, ctx)) ++ goto err; ++ ++ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, pub, decompressed_len, ctx); ++ ++err: ++ EC_POINT_free(point); ++ EC_GROUP_free(group); ++ BN_CTX_free(ctx); ++ ++ return len; ++} ++ ++static int ++get_uncompressed_ec_pubkey(EVP_PKEY *pkey, unsigned char *buf, size_t buf_len) ++{ ++ OSSL_PARAM params[2]; ++ size_t required_len = 0, out_len = 0; ++ ++ params[0] = OSSL_PARAM_construct_utf8_string( ++ OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, ++ "uncompressed", 0); ++ params[1] = OSSL_PARAM_construct_end(); ++ ++ if (EVP_PKEY_set_params(pkey, params) <= 0 ++ || EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, ++ buf, buf_len, &required_len) <= 0) { ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ ++ if (required_len != buf_len) { ++ /* Red Hat certified FIPS provider ignores OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT ++ * We may have to perform the conversion manually */ ++ if (len2curve_name(required_len) == len2curve_name(buf_len)) { ++ out_len = decompress_pub_key(buf, required_len, buf_len); ++ if (out_len != buf_len) { ++ debug_f("Error decompressing the compressed public key"); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } else { ++ return 0; ++ } ++ } else { ++ debug_f("Unexpected length of uncompressed public key: expected %d, got %d", buf_len, required_len); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ } ++ ++ return 0; ++} ++/* nist_bytes_len should always be uncompressed */ ++static int ++kex_kem_mlkem_nist_keypair(struct kex *kex, size_t mlkem_bytes_len, size_t nist_bytes_len) ++{ ++ struct sshbuf *buf = NULL; ++ u_char *cp = NULL; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ u_char *client_key = NULL; ++ ++ if ((buf = sshbuf_new()) == NULL) ++ return SSH_ERR_ALLOC_FAIL; ++ need = mlkem_bytes_len + nist_bytes_len; ++ if ((r = sshbuf_reserve(buf, need, &cp)) != 0) ++ goto out; ++ ++ if (mlkem_bytes_len == crypto_kem_mlkem768_PUBLICKEYBYTES) { ++ client_key = kex->mlkem768_client_key; ++ r = mlkem768_keypair_gen(cp, client_key); ++ } ++ ++ if (mlkem_bytes_len == crypto_kem_mlkem1024_PUBLICKEYBYTES) { ++ client_key = kex->mlkem1024_client_key; ++ r = mlkem1024_keypair_gen(cp, client_key); ++ } ++ ++ if (client_key == NULL) ++ goto out; ++ ++ if (r != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkemXXX:", cp, mlkem_bytes_len); ++#endif ++ cp += mlkem_bytes_len; ++ if ((kex->ec_hybrid_client_key = nist_pkey_keygen(nist_bytes_len)) == NULL) ++ goto out; ++ ++ if ((r = get_uncompressed_ec_pubkey(kex->ec_hybrid_client_key, cp, nist_bytes_len)) != 0) ++ goto out; ++ ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key NIST:", cp, nist_bytes_len); ++#endif ++ /* success */ ++ r = 0; ++ kex->client_pub = buf; ++ buf = NULL; ++ out: ++ sshbuf_free(buf); ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} ++ ++static int ++kex_kem_mlkem_nist_enc(struct kex *kex, const char *nist_curve, ++ const struct sshbuf *client_blob, struct sshbuf **server_blobp, ++ struct sshbuf **shared_secretp) ++{ ++ struct sshbuf *server_blob = NULL; ++ struct sshbuf *buf = NULL; ++ const u_char *client_pub; ++ u_char server_pub[NIST_BUF_MAX_SIZE]; ++ u_char enc_out[crypto_kem_mlkem1024_CIPHERTEXTBYTES]; ++ u_char secret[crypto_kem_mlkem768_BYTES]; ++ EVP_PKEY *server_key = NULL; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t client_buf_len, mlkem_buf_len, ecdh_buf_len, server_key_len, enc_out_len; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++ *server_blobp = NULL; ++ *shared_secretp = NULL; ++ ++ client_buf_len = sshbuf_len(client_blob); ++ /* client_blob contains both KEM and ECDH client pubkeys */ ++ if (strcmp(nist_curve, "P-256") == 0) { ++ if (crypto_kem_mlkem768_PUBLICKEYBYTES > client_buf_len) ++ return r; ++ ++ ecdh_buf_len = client_buf_len - crypto_kem_mlkem768_PUBLICKEYBYTES; ++ if (ecdh_buf_len != NIST_P256_COMPRESSED_LEN && ++ ecdh_buf_len != NIST_P256_UNCOMPRESSED_LEN) ++ return r; ++ mlkem_buf_len = crypto_kem_mlkem768_PUBLICKEYBYTES; ++ enc_out_len = crypto_kem_mlkem768_CIPHERTEXTBYTES; ++ server_key_len = NIST_P256_UNCOMPRESSED_LEN; ++ } else if (strcmp(nist_curve, "P-384") == 0) { ++ if (crypto_kem_mlkem1024_PUBLICKEYBYTES > client_buf_len) ++ return r; ++ ++ ecdh_buf_len = client_buf_len - crypto_kem_mlkem1024_PUBLICKEYBYTES; ++ if (ecdh_buf_len != NIST_P384_COMPRESSED_LEN && ++ ecdh_buf_len != NIST_P384_UNCOMPRESSED_LEN) ++ return r; ++ mlkem_buf_len = crypto_kem_mlkem1024_PUBLICKEYBYTES; ++ enc_out_len = crypto_kem_mlkem1024_CIPHERTEXTBYTES; ++ server_key_len = NIST_P384_UNCOMPRESSED_LEN; ++ } else ++ return r; ++ ++ client_pub = sshbuf_ptr(client_blob); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem:", client_pub, mlkem_buf_len); ++ dump_digest("client public key NIST:", client_pub + mlkem_buf_len, ecdh_buf_len); ++#endif ++ ++ /* allocate buffer for concatenation of KEM key and ECDH shared key */ ++ /* the buffer will be hashed and the result is the shared secret */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ /* allocate space for encrypted KEM key and ECDH pub key */ ++ if ((server_blob = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ r = (mlkem_buf_len == crypto_kem_mlkem768_PUBLICKEYBYTES) ? ++ mlkem768_encap_secret(client_pub, secret, enc_out) : ++ mlkem1024_encap_secret(client_pub, secret, enc_out); ++ ++ if (r != 0) ++ goto out; ++ ++ /* generate ECDH key pair, store server pubkey after ciphertext */ ++ server_key = nist_pkey_keygen(server_key_len); ++ ++ if ((r = get_uncompressed_ec_pubkey(server_key, server_pub, server_key_len) != 0) || ++ (r = sshbuf_put(buf, secret, sizeof(secret))) != 0 || ++ (r = sshbuf_put(server_blob, enc_out, enc_out_len) != 0)|| ++ (r = sshbuf_put(server_blob, server_pub, server_key_len)) != 0) ++ goto out; ++ ++ /* append ECDH shared key */ ++ client_pub += mlkem_buf_len; ++ if ((r = kex_nist_shared_key_ext(server_key, client_pub, ecdh_buf_len, buf)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("server public NIST:", server_pub, server_key_len); ++ dump_digest("server cipher text:", enc_out, enc_out_len); ++ dump_digest("server kem key:", secret, sizeof(secret)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* string-encoded hash is resulting shared secret */ ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *server_blobp = server_blob; ++ *shared_secretp = buf; ++ server_blob = NULL; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ EVP_PKEY_free(server_key); ++ explicit_bzero(enc_out, sizeof(enc_out)); ++ explicit_bzero(secret, sizeof(secret)); ++ sshbuf_free(server_blob); ++ sshbuf_free(buf); ++ return r; ++} ++ ++static int ++kex_kem_mlkem_nist_dec(struct kex *kex, ++ const struct sshbuf *server_blob, struct sshbuf **shared_secretp, ++ size_t mlkem_len) ++{ ++ struct sshbuf *buf = NULL; ++ const u_char *ciphertext, *server_pub; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ u_char decap[crypto_kem_mlkem768_BYTES]; ++ int r; ++ size_t nist_len; ++ ++ *shared_secretp = NULL; ++ ++ if (sshbuf_len(server_blob) < mlkem_len) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ ++ nist_len = sshbuf_len(server_blob) - mlkem_len; ++ ++ switch (mlkem_len) { ++ case crypto_kem_mlkem768_CIPHERTEXTBYTES: ++ if (nist_len != NIST_P256_COMPRESSED_LEN ++ && nist_len != NIST_P256_UNCOMPRESSED_LEN) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ break; ++ case crypto_kem_mlkem1024_CIPHERTEXTBYTES: ++ if (nist_len != NIST_P384_COMPRESSED_LEN ++ && nist_len != NIST_P384_UNCOMPRESSED_LEN) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ break; ++ } ++ ++ ciphertext = sshbuf_ptr(server_blob); ++ server_pub = ciphertext + mlkem_len; ++ /* hash concatenation of KEM key and ECDH shared key */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++#ifdef DEBUG_KEXECDH ++ dump_digest("server cipher text:", ciphertext, mlkem_len); ++ dump_digest("server public key NIST:", server_pub, nist_len); ++#endif ++ r = (mlkem_len == crypto_kem_mlkem768_CIPHERTEXTBYTES) ? ++ mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap) : ++ mlkem1024_decap_secret(kex->mlkem1024_client_key, ciphertext, decap); ++ ++ if (r != 0) ++ goto out; ++ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0) ++ goto out; ++ if ((r = kex_nist_shared_key_ext(kex->ec_hybrid_client_key, server_pub, ++ nist_len, buf)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, ++ hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client kem key:", decap, sizeof(decap)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *shared_secretp = buf; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(decap, sizeof(decap)); ++ sshbuf_free(buf); ++ return r; ++} ++ ++int ++kex_kem_mlkem768nistp256_keypair(struct kex *kex) ++{ ++ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem768_PUBLICKEYBYTES, NIST_P256_UNCOMPRESSED_LEN); ++} ++ ++int ++kex_kem_mlkem768nistp256_enc(struct kex *kex, const struct sshbuf *client_blob, ++ struct sshbuf **server_blobp, struct sshbuf **shared_secretp) ++{ ++ return kex_kem_mlkem_nist_enc(kex, "P-256", client_blob, server_blobp, shared_secretp); ++} ++ ++int ++kex_kem_mlkem768nistp256_dec(struct kex *kex, const struct sshbuf *server_blob, ++ struct sshbuf **shared_secretp) ++{ ++ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp, ++ crypto_kem_mlkem768_CIPHERTEXTBYTES); ++} ++ ++int ++kex_kem_mlkem1024nistp384_keypair(struct kex *kex) ++{ ++ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem1024_PUBLICKEYBYTES, NIST_P384_UNCOMPRESSED_LEN); ++} ++ ++int ++kex_kem_mlkem1024nistp384_enc(struct kex *kex, const struct sshbuf *client_blob, ++ struct sshbuf **server_blobp, struct sshbuf **shared_secretp) ++{ ++ return kex_kem_mlkem_nist_enc(kex, "P-384", client_blob, server_blobp, shared_secretp); ++} ++ ++int ++kex_kem_mlkem1024nistp384_dec(struct kex *kex, const struct sshbuf *server_blob, ++ struct sshbuf **shared_secretp) ++{ ++ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp, ++ crypto_kem_mlkem1024_CIPHERTEXTBYTES); ++} ++ + #else /* USE_MLKEM768X25519 */ + int + kex_kem_mlkem768x25519_keypair(struct kex *kex) +@@ -567,4 +1164,39 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, + { + return SSH_ERR_SIGN_ALG_UNSUPPORTED; + } ++ ++int kex_kem_mlkem768nistp256_keypair(struct kex *) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ ++int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *, ++ struct sshbuf **, struct sshbuf **) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ ++int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *, ++ struct sshbuf **) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ ++int kex_kem_mlkem1024nistp384_keypair(struct kex *) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ ++int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *, ++ struct sshbuf **, struct sshbuf **) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ ++int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *, ++ struct sshbuf **) ++{ ++ return SSH_ERR_SIGN_ALG_UNSUPPORTED; ++} ++ + #endif /* USE_MLKEM768X25519 */ +diff --git a/monitor.c b/monitor.c +index 6c83739ee..2f154a3d7 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -2014,6 +2014,8 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) + kex->kex[KEX_C25519_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; ++ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; ++ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; + kex->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; + kex->host_key_index=&get_hostkey_index; +diff --git a/myproposal.h b/myproposal.h +index 3e0ec6826..007347fc3 100644 +--- a/myproposal.h ++++ b/myproposal.h +@@ -26,6 +26,8 @@ + + #define KEX_SERVER_KEX \ + "mlkem768x25519-sha256," \ ++ "mlkem768nistp256-sha256," \ ++ "mlkem1024nistp384-sha384," \ + "sntrup761x25519-sha512," \ + "sntrup761x25519-sha512@openssh.com," \ + "curve25519-sha256," \ +@@ -97,6 +99,8 @@ + "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ + "aes128-gcm@openssh.com,aes256-gcm@openssh.com" + #define KEX_DEFAULT_KEX_FIPS \ ++ "mlkem768nistp256-sha256," \ ++ "mlkem1024nistp384-sha384," \ + "ecdh-sha2-nistp256," \ + "ecdh-sha2-nistp384," \ + "ecdh-sha2-nistp521," \ +diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c +index f4700deeb..99a8e3b46 100644 +--- a/regress/unittests/kex/test_kex.c ++++ b/regress/unittests/kex/test_kex.c +@@ -171,6 +171,8 @@ do_kex_with_key(char *kex, char *cipher, char *mac, + server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server; + server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; ++ server2->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; ++ server2->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; + server2->kex->load_host_public_key = server->kex->load_host_public_key; + server2->kex->load_host_private_key = server->kex->load_host_private_key; + server2->kex->sign = server->kex->sign; +@@ -248,6 +250,8 @@ kex_tests(void) + } + # ifdef USE_MLKEM768X25519 + do_kex("mlkem768x25519-sha256"); ++ do_kex("mlkem768nistp256-sha256"); ++ do_kex("mlkem1024nistp384-sha384"); + # endif /* USE_MLKEM768X25519 */ + # ifdef USE_SNTRUP761X25519 + do_kex("sntrup761x25519-sha512"); +diff --git a/ssh-keyscan.c b/ssh-keyscan.c +index 11618ae8a..2f4037972 100644 +--- a/ssh-keyscan.c ++++ b/ssh-keyscan.c +@@ -290,6 +290,8 @@ keygrab_ssh2(con *c) + c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + c->c_ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; ++ c->c_ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; ++ c->c_ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; + ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper); + /* + * do the key-exchange until an error occurs or until +diff --git a/ssh_api.c b/ssh_api.c +index 7bdcee148..d20b03a00 100644 +--- a/ssh_api.c ++++ b/ssh_api.c +@@ -135,6 +135,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) + ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; + ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; ++ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; ++ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; + ssh->kex->load_host_public_key=&_ssh_host_public_key; + ssh->kex->load_host_private_key=&_ssh_host_private_key; + ssh->kex->sign=&_ssh_host_key_sign; +@@ -154,6 +156,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) + ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; ++ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; ++ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; + ssh->kex->verify_host_key =&_ssh_verify_host_key; + } + *sshp = ssh; +diff --git a/sshconnect2.c b/sshconnect2.c +index 2d98fc3da..88e27955a 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -347,6 +347,8 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, + ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; ++ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; ++ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; + ssh->kex->verify_host_key=&verify_host_key_callback; + + #if defined(GSSAPI) && defined(WITH_OPENSSL) +diff --git a/sshd-auth.c b/sshd-auth.c +index f3c38a7d1..698ef83f3 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -893,6 +893,8 @@ do_ssh2_kex(struct ssh *ssh) + kex->kex[KEX_C25519_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; ++ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; ++ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; + kex->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; + kex->host_key_index=&get_hostkey_index; +-- +2.52.0 + diff --git a/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch b/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch new file mode 100644 index 0000000..85c4140 --- /dev/null +++ b/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch @@ -0,0 +1,139 @@ +From 71190d3d862113d97708a42b4a7daa7aa3c4e0ec Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Fri, 5 Dec 2025 14:55:38 +0100 +Subject: [PATCH 50/53] Provide a way to disable GSSAPIDelegateCredentials + server-side + +--- + gss-serv.c | 5 +++++ + servconf.c | 13 ++++++++++++- + servconf.h | 1 + + sshd_config.0 | 3 +++ + sshd_config.5 | 3 +++ + 5 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/gss-serv.c b/gss-serv.c +index be80e17ca..165484db0 100644 +--- a/gss-serv.c ++++ b/gss-serv.c +@@ -509,6 +509,11 @@ ssh_gssapi_cleanup_creds(void) + int + ssh_gssapi_storecreds(void) + { ++ if (options.gss_deleg_creds == 0) { ++ debug_f("delegate credential is disabled, doing nothing"); ++ return 0; ++ } ++ + if (gssapi_client.mech && gssapi_client.mech->storecreds) { + return (*gssapi_client.mech->storecreds)(&gssapi_client); + } else +diff --git a/servconf.c b/servconf.c +index e53e8ea30..fb1d150cd 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -143,6 +143,7 @@ initialize_server_options(ServerOptions *options) + options->gss_authentication=-1; + options->gss_keyex = -1; + options->gss_cleanup_creds = -1; ++ options->gss_deleg_creds = -1; + options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; +@@ -396,6 +397,8 @@ fill_default_server_options(ServerOptions *options) + options->gss_keyex = 0; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; ++ if (options->gss_deleg_creds == -1) ++ options->gss_deleg_creds = 1; + if (options->gss_strict_acceptor == -1) + options->gss_strict_acceptor = 1; + if (options->gss_store_rekey == -1) +@@ -591,7 +594,8 @@ typedef enum { + sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sPerSourcePenalties, sPerSourcePenaltyExemptList, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, +- sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, ++ sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, ++ sGssEnablek5users, sGssStrictAcceptor, + sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, +@@ -683,6 +687,7 @@ static struct { + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, + { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL }, + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, +@@ -693,6 +698,7 @@ static struct { + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, +@@ -1705,6 +1711,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, + intptr = &options->gss_cleanup_creds; + goto parse_flag; + ++ case sGssDelegateCreds: ++ intptr = &options->gss_deleg_creds; ++ goto parse_flag; ++ + case sGssStrictAcceptor: + intptr = &options->gss_strict_acceptor; + goto parse_flag; +@@ -3352,6 +3362,7 @@ dump_config(ServerOptions *o) + #ifdef GSSAPI + dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); + dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); ++ dump_cfg_fmtint(sGssDelegateCreds, o->gss_deleg_creds); + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); +diff --git a/servconf.h b/servconf.h +index c7cec5ece..9b1a73b8d 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -156,6 +156,7 @@ typedef struct { + int gss_authentication; /* If true, permit GSSAPI authentication */ + int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ ++ int gss_deleg_creds; /* If true, accept delegated GSS credentials */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; + char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ +diff --git a/sshd_config.0 b/sshd_config.0 +index 8c5217c0b..cda9c9182 100644 +--- a/sshd_config.0 ++++ b/sshd_config.0 +@@ -453,6 +453,9 @@ DESCRIPTION + Specifies whether to automatically destroy the user's credentials + cache on logout. The default is yes. + ++ GSSAPIDelegateCredentials ++ Accept delegated credentials on the server side. The default is yes. ++ + GSSAPIStrictAcceptorCheck + Determines whether to be strict about the identity of the GSSAPI + acceptor a client authenticates against. If set to yes then the +diff --git a/sshd_config.5 b/sshd_config.5 +index 676d6d4d2..4ae4bebee 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -733,6 +733,9 @@ Specifies whether to automatically destroy the user's credentials cache + on logout. + The default is + .Cm yes . ++.It Cm GSSAPIDelegateCredentials ++Accept delegated credentials on the server side. The default is ++.CM yes . + .It Cm GSSAPIEnablek5users + Specifies whether to look at .k5users file for GSSAPI authentication + access control. Further details are described in +-- +2.52.0 + diff --git a/openssh-7.3p1-x11-max-displays.patch b/0051-openssh-7.3p1-x11-max-displays.patch similarity index 52% rename from openssh-7.3p1-x11-max-displays.patch rename to 0051-openssh-7.3p1-x11-max-displays.patch index 2b702d4..422107c 100644 --- a/openssh-7.3p1-x11-max-displays.patch +++ b/0051-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 763c65f6f349a7bab344a58991246891700e4fa0 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Fri, 12 Dec 2025 15:35:14 +0100 +Subject: [PATCH 51/53] openssh-7.3p1-x11-max-displays + +--- + channels.c | 9 ++++++--- + channels.h | 2 +- + servconf.c | 12 +++++++++++- + servconf.h | 2 ++ + session.c | 5 +++-- + sshd_config.5 | 7 +++++++ + 6 files changed, 30 insertions(+), 7 deletions(-) + +diff --git a/channels.c b/channels.c +index 26ed9945f..c26380e25 100644 +--- a/channels.c ++++ b/channels.c +@@ -5067,7 +5067,7 @@ rdynamic_connect_finish(struct ssh *ssh, Channel *c) */ int x11_create_display_inet(struct ssh *ssh, int x11_display_offset, @@ -21,66 +25,33 @@ 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) +@@ -5080,8 +5080,11 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, + x11_display_offset > UINT16_MAX - X11_BASE_PORT - MAX_DISPLAYS) return -1; + /* Try to bind ports starting at 6000+X11DisplayOffset */ + x11_max_displays = x11_max_displays + x11_display_offset; + for (display_number = x11_display_offset; -- display_number < MAX_DISPLAYS; +- display_number < x11_display_offset + 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_ +@@ -5146,7 +5149,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_display_offset + MAX_DISPLAYS) { ++ 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 7456541f8..754bd98ee 100644 +--- a/channels.h ++++ b/channels.h +@@ -389,7 +389,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 fb1d150cd..956205f6d 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -118,6 +118,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 +@@ -357,6 +358,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, +@@ -582,7 +585,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 { +@@ -725,6 +728,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 +@@ -1775,6 +1779,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 +@@ -3037,6 +3045,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) +@@ -3332,6 +3341,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 9b1a73b8d..6bfdf6305 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 80282dfd8..e53d044a0 100644 +--- a/session.c ++++ b/session.c +@@ -2681,8 +2681,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 4ae4bebee..3dbce55fc 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1403,6 +1403,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 +@@ -2112,6 +2113,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.52.0 + diff --git a/openssh-8.0p1-pkcs11-uri.patch b/0052-openssh-10.2p1-pkcs11-uri.patch similarity index 80% rename from openssh-8.0p1-pkcs11-uri.patch rename to 0052-openssh-10.2p1-pkcs11-uri.patch index 551351c..b486fee 100644 --- a/openssh-8.0p1-pkcs11-uri.patch +++ b/0052-openssh-10.2p1-pkcs11-uri.patch @@ -1,7 +1,116 @@ -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 f32f2a8a37e8585c1259fea2a970319d229e2cc7 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Mon, 15 Dec 2025 14:24:07 +0100 +Subject: [PATCH 52/53] openssh-10.2p1-pkcs11-uri + +--- + Makefile.in | 24 +- + configure.ac | 37 ++ + regress/Makefile | 4 +- + regress/pkcs11.sh | 349 ++++++++++++++ + regress/unittests/Makefile | 2 +- + regress/unittests/pkcs11/tests.c | 353 ++++++++++++++ + ssh-add.c | 48 +- + ssh-agent.c | 104 ++++- + ssh-keygen.c | 7 +- + ssh-pkcs11-client.c | 17 + + ssh-pkcs11-uri.c | 437 ++++++++++++++++++ + ssh-pkcs11-uri.h | 43 ++ + ssh-pkcs11.c | 760 ++++++++++++++++++++++--------- + ssh-pkcs11.h | 4 + + ssh.c | 104 ++++- + ssh_config.5 | 15 + + 16 files changed, 2039 insertions(+), 269 deletions(-) + create mode 100644 regress/pkcs11.sh + create mode 100644 regress/unittests/pkcs11/tests.c + create mode 100644 ssh-pkcs11-uri.c + create mode 100644 ssh-pkcs11-uri.h + +diff --git a/Makefile.in b/Makefile.in +index 20d134c02..f8cbd545d 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -112,7 +112,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ + sshbuf-io.o misc-agent.o auditstub.o + +-P11OBJS= ssh-pkcs11-client.o ++P11OBJS= ssh-pkcs11-client.o ssh-pkcs11-uri.o + + SKOBJS= ssh-sk-client.o + +@@ -161,11 +161,11 @@ SSHADD_OBJS= ssh-add.o $(P11OBJS) $(SKOBJS) + + SSHAGENT_OBJS= ssh-agent.o $(P11OBJS) $(SKOBJS) + +-SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o ssh-pkcs11.o $(SKOBJS) ++SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o ssh-pkcs11.o ssh-pkcs11-uri.o $(SKOBJS) + + SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(P11OBJS) $(SKOBJS) + +-P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o $(SKOBJS) ++P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o ssh-pkcs11-uri.o $(SKOBJS) + + SKHELPER_OBJS= ssh-sk-helper.o ssh-sk.o sk-usbhid.o + +@@ -331,6 +331,8 @@ clean: regressclean + rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT) + rm -f regress/unittests/utf8/*.o + rm -f regress/unittests/utf8/test_utf8$(EXEEXT) ++ rm -f regress/unittests/pkcs11/*.o ++ rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) + rm -f regress/misc/sk-dummy/*.o + rm -f regress/misc/sk-dummy/*.lo + rm -f regress/misc/ssh-verify-attestation/ssh-verify-attestation$(EXEEXT) +@@ -369,6 +371,8 @@ distclean: regressclean + rm -f regress/unittests/sshsig/test_sshsig + rm -f regress/unittests/utf8/*.o + rm -f regress/unittests/utf8/test_utf8 ++ rm -f regress/unittests/pkcs11/*.o ++ rm -f regress/unittests/pkcs11/test_pkcs11 + rm -f regress/misc/sk-dummy/*.o + rm -f regress/misc/sk-dummy/*.lo + rm -f regress/misc/sk-dummy/sk-dummy.so +@@ -549,6 +553,7 @@ regress-prep: + $(MKDIR_P) `pwd`/regress/unittests/sshkey + $(MKDIR_P) `pwd`/regress/unittests/sshsig + $(MKDIR_P) `pwd`/regress/unittests/utf8 ++ $(MKDIR_P) `pwd`/regress/unittests/pkcs11 + $(MKDIR_P) `pwd`/regress/misc/sk-dummy + $(MKDIR_P) `pwd`/regress/misc/ssh-verify-attestation + [ -f `pwd`/regress/Makefile ] || \ +@@ -724,6 +729,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT): \ + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS) + ++UNITTESTS_TEST_PKCS11_OBJS=\ ++ regress/unittests/pkcs11/tests.o ++ ++regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \ ++ ${UNITTESTS_TEST_PKCS11_OBJS} ssh-pkcs11-uri.o \ ++ regress/unittests/test_helper/libtest_helper.a libssh.a ++ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \ ++ regress/unittests/test_helper/libtest_helper.a \ ++ ssh-pkcs11-uri.o -lssh -lopenbsd-compat -lcrypto $(LIBS) -lm ++ + # These all need to be compiled -fPIC, so they are treated differently. + SK_DUMMY_OBJS=\ + regress/misc/sk-dummy/sk-dummy.lo \ +@@ -769,7 +784,8 @@ regress-unit-binaries: regress-prep $(REGRESSLIBS) \ + regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ + regress/unittests/sshkey/test_sshkey$(EXEEXT) \ + regress/unittests/sshsig/test_sshsig$(EXEEXT) \ +- regress/unittests/utf8/test_utf8$(EXEEXT) ++ regress/unittests/utf8/test_utf8$(EXEEXT) \ ++ regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ + + tests: file-tests t-exec interop-tests extra-tests unit + echo all tests passed +diff --git a/configure.ac b/configure.ac +index 9d3b19925..e33462027 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2246,12 +2246,14 @@ AC_LINK_IFELSE( [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) ]) @@ -16,7 +125,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]) +@@ -2281,6 +2283,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([dlopen]) AC_CHECK_DECL([RTLD_NOW], [], [], [#include ]) @@ -57,7 +166,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 +@@ -5904,6 +5940,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 +174,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 -@@ -105,7 +105,7 @@ - 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 -@@ -685,6 +690,16 @@ - 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 ece093a2b..a851549f6 100644 +--- a/regress/Makefile ++++ b/regress/Makefile +@@ -139,7 +139,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,21 +188,19 @@ 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: - V="" ; \ - test "x${USE_VALGRIND}" = "x" || \ - V=${.CURDIR}/valgrind-unit.sh ; \ -- $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ -- $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -+ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ -+ $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ -+ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ - -d ${.CURDIR}/unittests/sshkey/testdata ; \ - $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \ - -d ${.CURDIR}/unittests/sshsig/testdata ; \ -diff -up openssh-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 +@@ -288,6 +289,7 @@ unit unit-bench: + test "x${UNITTEST_VERBOSE}" = "x" || ARGS="$$ARGS -v"; \ + test "x${UNITTEST_BENCH_DETAIL}" = "x" || ARGS="$$ARGS -B"; \ + test "x${UNITTEST_BENCH_ONLY}" = "x" || ARGS="$$ARGS -O ${UNITTEST_BENCH_ONLY}"; \ ++ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ + $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf $${ARGS}; \ + $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ + -d ${.CURDIR}/unittests/sshkey/testdata $${ARGS}; \ +diff --git a/regress/pkcs11.sh b/regress/pkcs11.sh +new file mode 100644 +index 000000000..a91aee94f +--- /dev/null ++++ b/regress/pkcs11.sh @@ -0,0 +1,349 @@ +# +# Copyright (c) 2017 Red Hat @@ -520,21 +551,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 e370900e4..d6c89c129 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,346 @@ +diff --git a/regress/unittests/pkcs11/tests.c b/regress/unittests/pkcs11/tests.c +new file mode 100644 +index 000000000..89ba45c4e +--- /dev/null ++++ b/regress/unittests/pkcs11/tests.c +@@ -0,0 +1,353 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -881,23 +915,35 @@ 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 @@ ++ ++void ++benchmarks(void) ++{ ++ printf("no benchmarks\n"); ++} ++ +diff --git a/ssh-add.c b/ssh-add.c +index 2d5bec89c..aae82a794 100644 +--- a/ssh-add.c ++++ b/ssh-add.c +@@ -70,6 +70,7 @@ #include "ssh-sk.h" #include "sk-api.h" #include "hostfile.h" +#include "ssh-pkcs11-uri.h" - /* argv0 */ - extern char *__progname; -@@ -229,6 +230,34 @@ delete_all(int agent_fd, int qflag) - return ret; + #define CERT_EXPIRY_GRACE (5*60) + +@@ -257,6 +258,38 @@ check_cert_lifetime(const struct sshkey *cert, int cert_lifetime) + return MINIMUM(cert_lifetime, (int)n); } +#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, @@ -919,32 +965,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, int Nflag, const char *skprovider, +@@ -447,15 +480,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) +@@ -637,6 +669,14 @@ do_file(int agent_fd, int deleting, int key_only, int cert_only, + char *file, int qflag, int Nflag, const char *skprovider, + struct dest_constraint **dest_constraints, size_t ndest_constraints) { +#ifdef ENABLE_PKCS11 + if (strlen(file) >= strlen(PKCS11_URI_SCHEME) && @@ -955,24 +1004,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) +@@ -1009,7 +1049,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) + for (n = 0; n < ncerts; n++) + sshkey_free(certs[n]); +diff --git a/ssh-agent.c b/ssh-agent.c +index dc246066d..c3e94e2b1 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1540,10 +1540,75 @@ add_p11_identity(struct sshkey *key, char *comment, const char *provider, + idtab->nentries++; } - #ifdef ENABLE_PKCS11 +static char * +sanitize_pkcs11_provider(const char *provider) +{ @@ -983,6 +1033,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) { @@ -995,6 +1047,7 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c + + 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 */ @@ -1043,8 +1096,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"); +@@ -1572,25 +1637,18 @@ process_add_smartcard_key(SocketEntry *e) + "providers is disabled", provider); goto send; } - if (realpath(provider, canonical_provider) == NULL) { @@ -1055,13 +1108,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; @@ -1069,31 +1120,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])) +@@ -1600,13 +1658,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 */ +@@ -1619,6 +1677,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); +@@ -1631,7 +1690,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { @@ -1102,7 +1160,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 +@@ -1643,30 +1702,29 @@ process_remove_smartcard_key(SocketEntry *e) } free(pin); @@ -1139,185 +1197,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 afa279097..7af08fcdf 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -831,8 +831,11 @@ do_download(struct passwd *pw) free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ @@ -1331,1311 +1215,52 @@ 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 85afb62ac..7b7eaf533 100644 +--- a/ssh-pkcs11-client.c ++++ b/ssh-pkcs11-client.c +@@ -378,6 +378,19 @@ pkcs11_start_helper(const char *path) + return helper; + } + ++int ++pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp, char ***labelsp) ++{ ++ int nkeys = 0; ++ char *provider_uri = pkcs11_uri_get(uri); ++ ++ debug_f("called, provider_uri = %s", provider_uri); ++ ++ nkeys = pkcs11_add_provider(provider_uri, pin, keyp, labelsp); ++ ++ return nkeys; ++} ++ + int + pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, + char ***labelsp) +@@ -389,6 +403,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, 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; +@@ -413,6 +429,7 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); if (labelsp) *labelsp = xcalloc(nkeys, sizeof(char *)); + debug_f("nkeys = %u", nkeys); for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ - if ((r = 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,56 @@ static EC_KEY_METHOD *ec_key_method; - static int ec_key_idx = 0; - #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - -+/* -+ * This can't be in the ssh-pkcs11-uri, becase we can not depend on -+ * PKCS#11 structures in ssh-agent (using client-helper communication) -+ */ -+int -+pkcs11_uri_write(const struct sshkey *key, FILE *f) -+{ -+ char *p = NULL; -+ struct pkcs11_uri uri; -+ struct pkcs11_key *k11; -+ -+ /* sanity - is it a RSA key with associated app_data? */ -+ switch (key->type) { -+ case KEY_RSA: -+ k11 = RSA_get_ex_data(key->rsa, rsa_idx); -+ break; -+#ifdef HAVE_EC_KEY_METHOD_NEW -+ case KEY_ECDSA: -+ k11 = EC_KEY_get_ex_data(key->ecdsa, ec_key_idx); -+ break; -+#endif -+ default: -+ error("Unknown key type %d", key->type); -+ return -1; -+ } -+ if (k11 == NULL) { -+ error("Failed to get ex_data for key type %d", key->type); -+ return (-1); -+ } -+ -+ /* omit type -- we are looking for private-public or private-certificate pairs */ -+ uri.id = k11->keyid; -+ uri.id_len = k11->keyid_len; -+ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; -+ uri.object = k11->label; -+ uri.module_path = k11->provider->module->module_path; -+ uri.lib_manuf = k11->provider->module->info.manufacturerID; -+ uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; -+ uri.serial = k11->provider->module->slotinfo[k11->slotidx].token.serialNumber; -+ -+ p = pkcs11_uri_get(&uri); -+ /* do not cleanup -- we do not allocate here, only reference */ -+ if (p == NULL) -+ return -1; -+ -+ fprintf(f, " %s", p); -+ free(p); -+ return 0; -+} -+ - /* release a wrapped object */ - static void - pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, -@@ -208,6 +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); -@@ -260,14 +403,14 @@ pkcs11_login_slot(struct pkcs11_provider - if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) - verbose("Deferring PIN entry to reader keypad."); - else { -- snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", -+ snprintf(prompt, sizeof(prompt), "Enter PIN for '%.32s': ", - si->token.label); -- if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) { -+ if ((pin = read_passphrase(prompt, RP_ALLOW_EOF|RP_ALLOW_STDIN)) == NULL) { - debug_f("no pin specified"); - return (-1); /* bail out */ - } - } -- rv = provider->function_list->C_Login(si->session, type, (u_char *)pin, -+ rv = provider->module->function_list->C_Login(si->session, type, (u_char *)pin, - (pin != NULL) ? strlen(pin) : 0); - if (pin != NULL) - freezero(pin, strlen(pin)); -@@ -297,13 +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); - -@@ -622,7 +779,8 @@ - } - #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 void - rmspace(u_char *buf, size_t len) - { -@@ -630,8 +788,8 @@ - - if (!len) - return; -- for (i = len - 1; i > 0; i--) -- if (i == len - 1 || buf[i] == ' ') -+ for (i = len - 1; i > 0; i--) -+ if (buf[i] == ' ') - buf[i] = '\0'; - else - break; -@@ -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,305 @@ - 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(p->info.manufacturerID, sizeof(p->info.manufacturerID)); -- rmspace(p->info.libraryDescription, sizeof(p->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) { -+ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); -+ if (uri->lib_manuf != NULL && -+ strncmp(uri->lib_manuf, m->info.manufacturerID, 32)) { -+ debug_f("Skipping provider %s not matching library_manufacturer", -+ m->info.manufacturerID); -+ goto fail; -+ } -+ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); -+ debug("provider %s: manufacturerID <%.32s> cryptokiVersion %d.%d" -+ " libraryDescription <%.32s> libraryVersion %d.%d", -+ provider_module, -+ m->info.manufacturerID, -+ m->info.cryptokiVersion.major, -+ m->info.cryptokiVersion.minor, -+ m->info.libraryDescription, -+ m->info.libraryVersion.major, -+ m->info.libraryVersion.minor); -+ -+ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { - error("C_GetSlotList failed: %lu", rv); - goto fail; - } -- if (p->nslots == 0) { -- debug_f("provider %s returned no slots", provider_id); -+ if (m->nslots == 0) { -+ debug_f("provider %s returned no slots", provider_module); - ret = -SSH_PKCS11_ERR_NO_SLOTS; - goto fail; - } -- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); -- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) -+ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); -+ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) - != CKR_OK) { - error("C_GetSlotList for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); - 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)); -- debug("provider %s slot %lu: label <%s> manufacturerID <%s> " -- "model <%s> serial <%s> flags 0x%lx", -- provider_id, (unsigned long)i, -+ } -+ 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 && -+ 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 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 (%.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) { -@@ -1684,7 +2012,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 + if ((r = sshkey_froms(msg, &k)) != 0 || +diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c +new file mode 100644 +index 000000000..8bd97e9e2 +--- /dev/null ++++ b/ssh-pkcs11-uri.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2017 Red Hat @@ -3074,9 +1699,11 @@ 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 +diff --git a/ssh-pkcs11-uri.h b/ssh-pkcs11-uri.h +new file mode 100644 +index 000000000..29e9f7327 +--- /dev/null ++++ b/ssh-pkcs11-uri.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Red Hat @@ -3121,3 +1748,1506 @@ 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 c88179473..1a443824d 100644 +--- a/ssh-pkcs11.c ++++ b/ssh-pkcs11.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #endif + + #define CRYPTOKI_COMPAT +@@ -51,6 +52,7 @@ + #include "misc.h" + #include "sshbuf.h" + #include "ssh-pkcs11.h" ++#include "ssh-pkcs11-uri.h" + #include "digest.h" + #include "xmalloc.h" + #include "crypto_api.h" +@@ -61,8 +63,8 @@ struct pkcs11_slotinfo { + int logged_in; + }; + +-struct pkcs11_provider { +- char *name; ++struct pkcs11_module { ++ char *module_path; + void *handle; + CK_FUNCTION_LIST *function_list; + CK_INFO info; +@@ -71,6 +73,13 @@ struct pkcs11_provider { + struct pkcs11_slotinfo *slotinfo; + int valid; + int refcount; ++}; ++ ++struct pkcs11_provider { ++ char *name; ++ struct pkcs11_module *module; /* can be shared between various providers */ ++ int refcount; ++ int valid; + TAILQ_ENTRY(pkcs11_provider) next; + }; + +@@ -82,6 +91,7 @@ struct pkcs11_key { + CK_ULONG slotidx; + char *keyid; + int keyid_len; ++ char *label; + TAILQ_ENTRY(pkcs11_key) next; + }; + +@@ -108,26 +118,61 @@ ossl_error(const char *msg) + * this is called when a provider gets unregistered. + */ + static void +-pkcs11_provider_finalize(struct pkcs11_provider *p) ++pkcs11_module_finalize(struct pkcs11_module *m) + { + CK_RV rv; + CK_ULONG i; + +- debug_f("provider \"%s\" refcount %d valid %d", +- p->name, p->refcount, p->valid); +- if (!p->valid) ++ debug_f("%p refcount %d valid %d", m, m->refcount, m->valid); ++ if (!m->valid) + return; +- for (i = 0; i < p->nslots; i++) { +- if (p->slotinfo[i].session && +- (rv = p->function_list->C_CloseSession( +- p->slotinfo[i].session)) != CKR_OK) ++ for (i = 0; i < m->nslots; i++) { ++ if (m->slotinfo[i].session && ++ (rv = m->function_list->C_CloseSession( ++ m->slotinfo[i].session)) != CKR_OK) + error("C_CloseSession failed: %lu", rv); + } +- if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) ++ if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize failed: %lu", rv); ++ m->valid = 0; ++ m->function_list = NULL; ++ dlclose(m->handle); ++} ++ ++/* ++ * remove a reference to the pkcs11 module. ++ * called when a provider is unregistered. ++ */ ++static void ++pkcs11_module_unref(struct pkcs11_module *m) ++{ ++ debug_f("%p refcount %d", m, m->refcount); ++ if (--m->refcount <= 0) { ++ pkcs11_module_finalize(m); ++ if (m->valid) ++ error_f("%p still valid", m); ++ free(m->slotlist); ++ free(m->slotinfo); ++ free(m->module_path); ++ free(m); ++ } ++} ++ ++/* ++ * finalize a provider shared library, it's no longer usable. ++ * however, there might still be keys referencing this provider, ++ * so the actual freeing of memory is handled by pkcs11_provider_unref(). ++ * this is called when a provider gets unregistered. ++ */ ++static void ++pkcs11_provider_finalize(struct pkcs11_provider *p) ++{ ++ debug_f("%p refcount %d valid %d", p, p->refcount, p->valid); ++ if (!p->valid) ++ return; ++ pkcs11_module_unref(p->module); ++ p->module = NULL; + p->valid = 0; +- p->function_list = NULL; +- dlclose(p->handle); + } + + /* +@@ -139,15 +184,27 @@ pkcs11_provider_unref(struct pkcs11_provider *p) + { + debug_f("provider \"%s\" refcount %d", p->name, p->refcount); + if (--p->refcount <= 0) { +- if (p->valid) +- error_f("provider \"%s\" still valid", p->name); + free(p->name); +- free(p->slotlist); +- free(p->slotinfo); ++ if (p->module) ++ pkcs11_module_unref(p->module); + free(p); + } + } + ++/* lookup provider by module path */ ++static struct pkcs11_module * ++pkcs11_provider_lookup_module(char *module_path) ++{ ++ struct pkcs11_provider *p; ++ ++ TAILQ_FOREACH(p, &pkcs11_providers, next) { ++ debug("check %p %s (%s)", p, p->name, p->module->module_path); ++ if (!strcmp(module_path, p->module->module_path)) ++ return (p->module); ++ } ++ return (NULL); ++} ++ + /* lookup provider by name */ + static struct pkcs11_provider * + pkcs11_provider_lookup(char *provider_id) +@@ -162,19 +219,55 @@ pkcs11_provider_lookup(char *provider_id) + return (NULL); + } + ++int pkcs11_del_provider_by_uri(struct pkcs11_uri *); ++ + /* unregister provider by name */ + int + pkcs11_del_provider(char *provider_id) ++{ ++ int rv; ++ struct pkcs11_uri *uri; ++ ++ debug_f("called, provider_id = %s", provider_id); ++ ++ if (provider_id == NULL) ++ return 0; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ rv = pkcs11_del_provider_by_uri(uri); ++ pkcs11_uri_cleanup(uri); ++ return rv; ++} ++ ++/* unregister provider by PKCS#11 URI */ ++int ++pkcs11_del_provider_by_uri(struct pkcs11_uri *uri) + { + struct pkcs11_provider *p; ++ int rv = -1; ++ char *provider_uri = pkcs11_uri_get(uri); + +- if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { ++ debug3_f("called with provider %s", provider_uri); ++ ++ if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); +- return (0); ++ rv = 0; + } +- return (-1); ++ free(provider_uri); ++ return rv; + } + + /* release a wrapped object */ +@@ -186,6 +279,7 @@ pkcs11_k11_free(struct pkcs11_key *k11) + if (k11->provider) + pkcs11_provider_unref(k11->provider); + free(k11->keyid); ++ free(k11->label); + sshbuf_free(k11->keyblob); + free(k11); + } +@@ -201,8 +295,8 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, + CK_RV rv; + int ret = -1; + +- f = p->function_list; +- session = p->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ session = p->module->slotinfo[slotidx].session; + if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { + error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); + return (-1); +@@ -239,14 +333,14 @@ pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, + if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) + verbose("Deferring PIN entry to reader keypad."); + else { +- snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", ++ snprintf(prompt, sizeof(prompt), "Enter PIN for '%.32s': ", + si->token.label); +- if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) { ++ if ((pin = read_passphrase(prompt, RP_ALLOW_EOF|RP_ALLOW_STDIN)) == NULL) { + debug_f("no pin specified"); + return (-1); /* bail out */ + } + } +- rv = provider->function_list->C_Login(si->session, type, (u_char *)pin, ++ rv = provider->module->function_list->C_Login(si->session, type, (u_char *)pin, + (pin != NULL) ? strlen(pin) : 0); + if (pin != NULL) + freezero(pin, strlen(pin)); +@@ -276,13 +370,14 @@ pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, + static int + pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) + { +- if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) { ++ if (k11 == NULL || k11->provider == NULL || !k11->provider->valid || ++ k11->provider->module == NULL || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + + return pkcs11_login_slot(k11->provider, +- &k11->provider->slotinfo[k11->slotidx], type); ++ &k11->provider->module->slotinfo[k11->slotidx], type); + } + + +@@ -298,13 +393,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj, + + *val = 0; + +- if (!k11->provider || !k11->provider->valid) { ++ if (!k11->provider || !k11->provider->valid || ++ !k11->provider->module || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + attr.type = type; + attr.pValue = &flag; +@@ -335,13 +431,14 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) + int always_auth = 0; + int did_login = 0; + +- if (!k11->provider || !k11->provider->valid) { ++ if (!k11->provider || !k11->provider->valid || ++ !k11->provider->module || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { + if (pkcs11_login(k11, CKU_USER) < 0) { +@@ -440,6 +537,12 @@ pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx, + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + } ++ if (keyid_attrib->ulValueLen > 0 ) { ++ k11->label = xmalloc(keyid_attrib->ulValueLen+1); ++ memcpy(k11->label, keyid_attrib->pValue, keyid_attrib->ulValueLen); ++ k11->label[keyid_attrib->ulValueLen] = 0; ++ } ++ + TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next); + + return 0; +@@ -467,6 +570,42 @@ pkcs11_lookup_key(struct sshkey *key) + return found; + } + ++/* ++ * This can't be in the ssh-pkcs11-uri, becase we can not depend on ++ * PKCS#11 structures in ssh-agent (using client-helper communication) ++ */ ++int ++pkcs11_uri_write(const struct sshkey *key, FILE *f) ++{ ++ char *p = NULL; ++ struct pkcs11_uri uri; ++ struct pkcs11_key *k11 = pkcs11_lookup_key(key); ++ ++ if (k11 == NULL) { ++ error("Failed to get ex_data for key type %d", key->type); ++ return (-1); ++ } ++ ++ /* omit type -- we are looking for private-public or private-certificate pairs */ ++ uri.id = k11->keyid; ++ uri.id_len = k11->keyid_len; ++ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; ++ uri.object = k11->label; ++ uri.module_path = k11->provider->module->module_path; ++ uri.lib_manuf = k11->provider->module->info.manufacturerID; ++ uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; ++ uri.serial = k11->provider->module->slotinfo[k11->slotidx].token.serialNumber; ++ ++ p = pkcs11_uri_get(&uri); ++ /* do not cleanup -- we do not allocate here, only reference */ ++ if (p == NULL) ++ return -1; ++ ++ fprintf(f, " %s", p); ++ free(p); ++ return 0; ++} ++ + #ifdef WITH_OPENSSL + /* + * See: +@@ -571,8 +710,8 @@ pkcs11_sign_rsa(struct sshkey *key, + return SSH_ERR_AGENT_FAILURE; + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + if ((siglen = EVP_PKEY_size(key->pkey)) <= 0) + return SSH_ERR_INVALID_ARGUMENT; +@@ -661,8 +800,8 @@ pkcs11_sign_ecdsa(struct sshkey *key, + debug3_f("sign using provider %s slotidx %lu", + k11->provider->name, (u_long)k11->slotidx); + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + /* Prepare digest to be signed */ + if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) +@@ -746,8 +885,8 @@ pkcs11_sign_ed25519(struct sshkey *key, + debug3_f("sign using provider %s slotidx %lu", + k11->provider->name, (u_long)k11->slotidx); + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + xdata = xmalloc(datalen); + memcpy(xdata, data, datalen); +@@ -775,7 +914,8 @@ pkcs11_sign_ed25519(struct sshkey *key, + return ret; + } + +-/* remove trailing spaces */ ++/* remove trailing spaces. Note, that this does NOT guarantee the buffer ++ * will be null terminated if there are no trailing spaces! */ + static char * + rmspace(u_char *buf, size_t len) + { +@@ -807,8 +947,8 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin, + CK_SESSION_HANDLE session; + int login_required, ret; + +- f = p->function_list; +- si = &p->slotinfo[slotidx]; ++ f = p->module->function_list; ++ si = &p->module->slotinfo[slotidx]; + + login_required = si->token.flags & CKF_LOGIN_REQUIRED; + +@@ -818,9 +958,9 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin, + error("pin required"); + return (-SSH_PKCS11_ERR_PIN_REQUIRED); + } +- if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| ++ if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION| + CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) { +- error("C_OpenSession failed: %lu", rv); ++ error("C_OpenSession failed for slot %lu: %lu", slotidx, rv); + return (-1); + } + if (login_required && pin != NULL && strlen(pin) != 0) { +@@ -857,7 +997,8 @@ static struct sshkey * + pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) + { +- CK_ATTRIBUTE key_attr[3]; ++ CK_ATTRIBUTE key_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -870,14 +1011,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; +- key_attr[1].type = CKA_EC_POINT; +- key_attr[2].type = CKA_EC_PARAMS; ++ key_attr[1].type = CKA_LABEL; ++ key_attr[2].type = CKA_EC_POINT; ++ key_attr[3].type = CKA_EC_PARAMS; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); +@@ -888,19 +1030,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + * ensure that none of the others are zero length. + * XXX assumes CKA_ID is always first. + */ +- if (key_attr[1].ulValueLen == 0 || +- key_attr[2].ulValueLen == 0) { ++ if (key_attr[2].ulValueLen == 0 || ++ key_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + + /* retrieve ID, public point and curve parameters of EC key */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; +@@ -912,8 +1054,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + goto fail; + } + +- attrp = key_attr[2].pValue; +- group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen); ++ attrp = key_attr[3].pValue; ++ group = d2i_ECPKParameters(NULL, &attrp, key_attr[3].ulValueLen); + if (group == NULL) { + ossl_error("d2i_ECPKParameters failed"); + goto fail; +@@ -924,13 +1066,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + goto fail; + } + +- if (key_attr[1].ulValueLen <= 2) { ++ if (key_attr[2].ulValueLen <= 2) { + error("CKA_EC_POINT too small"); + goto fail; + } + +- attrp = key_attr[1].pValue; +- octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen); ++ attrp = key_attr[2].pValue; ++ octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[2].ulValueLen); + if (octet == NULL) { + ossl_error("d2i_ASN1_OCTET_STRING failed"); + goto fail; +@@ -992,7 +1134,8 @@ static struct sshkey * + pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) + { +- CK_ATTRIBUTE key_attr[3]; ++ CK_ATTRIBUTE key_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1003,14 +1146,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; +- key_attr[1].type = CKA_MODULUS; +- key_attr[2].type = CKA_PUBLIC_EXPONENT; ++ key_attr[1].type = CKA_LABEL; ++ key_attr[2].type = CKA_MODULUS; ++ key_attr[3].type = CKA_PUBLIC_EXPONENT; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); +@@ -1021,19 +1165,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + * ensure that none of the others are zero length. + * XXX assumes CKA_ID is always first. + */ +- if (key_attr[1].ulValueLen == 0 || +- key_attr[2].ulValueLen == 0) { ++ if (key_attr[2].ulValueLen == 0 || ++ key_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + + /* retrieve ID, modulus and public exponent of RSA key */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; +@@ -1045,8 +1189,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + goto fail; + } + +- rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL); +- rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); ++ rsa_n = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); ++ rsa_e = BN_bin2bn(key_attr[3].pValue, key_attr[3].ulValueLen, NULL); + if (rsa_n == NULL || rsa_e == NULL) { + error("BN_bin2bn failed"); + goto fail; +@@ -1078,7 +1222,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + /* success */ + success = 0; + fail: +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(key_attr[i].pValue); + RSA_free(rsa); + if (success != 0) { +@@ -1093,7 +1237,8 @@ static struct sshkey * + pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) + { +- CK_ATTRIBUTE key_attr[3]; ++ CK_ATTRIBUTE key_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1113,14 +1258,15 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; +- key_attr[1].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */ +- key_attr[2].type = CKA_EC_PARAMS; ++ key_attr[1].type = CKA_LABEL; ++ key_attr[2].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */ ++ key_attr[3].type = CKA_EC_PARAMS; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); +@@ -1131,28 +1277,28 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + * ensure that none of the others are zero length. + * XXX assumes CKA_ID is always first. + */ +- if (key_attr[1].ulValueLen == 0 || +- key_attr[2].ulValueLen == 0) { ++ if (key_attr[2].ulValueLen == 0 || ++ key_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) { ++ for (i = 0; i < nattr; i++) { + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + } + + /* retrieve ID, public point and curve parameters of EC key */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; + } + + /* Expect one of the supported identifiers in CKA_EC_PARAMS */ +- d = (u_char *)key_attr[2].pValue; +- len = key_attr[2].ulValueLen; ++ d = (u_char *)key_attr[3].pValue; ++ len = key_attr[3].ulValueLen; + if ((len != sizeof(id1) || memcmp(d, id1, sizeof(id1)) != 0) && + (len != sizeof(id2) || memcmp(d, id2, sizeof(id2)) != 0)) { + hex = tohex(d, len); +@@ -1164,16 +1310,16 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + * Expect either a raw 32 byte pubkey or an OCTET STRING with + * a 32 byte pubkey in CKA_VALUE + */ +- d = (u_char *)key_attr[1].pValue; +- len = key_attr[1].ulValueLen; ++ d = (u_char *)key_attr[2].pValue; ++ len = key_attr[2].ulValueLen; + if (len == ED25519_PK_SZ + 2 && d[0] == 0x04 && d[1] == ED25519_PK_SZ) { + d += 2; + len -= 2; + } + if (len != ED25519_PK_SZ) { +- hex = tohex(key_attr[1].pValue, key_attr[1].ulValueLen); ++ hex = tohex(key_attr[2].pValue, key_attr[2].ulValueLen); + logit_f("CKA_EC_POINT invalid octet str: %s (len %lu)", +- hex, (u_long)key_attr[1].ulValueLen); ++ hex, (u_long)key_attr[2].ulValueLen); + goto fail; + } + +@@ -1193,7 +1339,7 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + key = NULL; + } + free(hex); +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(key_attr[i].pValue); + return key; + } +@@ -1203,7 +1349,8 @@ static int + pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) + { +- CK_ATTRIBUTE cert_attr[3]; ++ CK_ATTRIBUTE cert_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1229,14 +1376,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + + memset(&cert_attr, 0, sizeof(cert_attr)); + cert_attr[0].type = CKA_ID; +- cert_attr[1].type = CKA_SUBJECT; +- cert_attr[2].type = CKA_VALUE; ++ cert_attr[1].type = CKA_LABEL; ++ cert_attr[2].type = CKA_SUBJECT; ++ cert_attr[3].type = CKA_VALUE; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return -1; +@@ -1248,18 +1396,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + * XXX assumes CKA_ID is always first. + */ + if (cert_attr[1].ulValueLen == 0 || +- cert_attr[2].ulValueLen == 0) { ++ cert_attr[2].ulValueLen == 0 || ++ cert_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return -1; + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (cert_attr[i].ulValueLen > 0) + cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen); + + /* retrieve ID, subject and value of certificate */ +- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto out; +@@ -1273,8 +1422,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + subject = xstrdup("invalid subject"); + X509_NAME_free(x509_name); + +- cp = cert_attr[2].pValue; +- if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) { ++ cp = cert_attr[3].pValue; ++ if ((x509 = d2i_X509(NULL, &cp, cert_attr[3].ulValueLen)) == NULL) { + error("d2i_x509 failed"); + goto out; + } +@@ -1384,7 +1533,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + goto out; + } + out: +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(cert_attr[i].pValue); + X509_free(x509); + RSA_free(rsa); +@@ -1427,11 +1576,12 @@ note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context, + */ + static int + pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, +- struct sshkey ***keysp, char ***labelsp, int *nkeys) ++ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) + { + struct sshkey *key = NULL; + CK_OBJECT_CLASS key_class; +- CK_ATTRIBUTE key_attr[1]; ++ CK_ATTRIBUTE key_attr[3]; ++ int nattr = 1; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1448,10 +1598,23 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, + key_attr[0].pValue = &key_class; + key_attr[0].ulValueLen = sizeof(key_class); + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ if (uri->id != NULL) { ++ key_attr[nattr].type = CKA_ID; ++ key_attr[nattr].pValue = uri->id; ++ key_attr[nattr].ulValueLen = uri->id_len; ++ nattr++; ++ } ++ if (uri->object != NULL) { ++ key_attr[nattr].type = CKA_LABEL; ++ key_attr[nattr].pValue = uri->object; ++ key_attr[nattr].ulValueLen = strlen(uri->object); ++ nattr++; ++ } + +- rv = f->C_FindObjectsInit(session, key_attr, 1); ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ ++ rv = f->C_FindObjectsInit(session, key_attr, nattr); + if (rv != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + goto fail; +@@ -1533,11 +1696,12 @@ fail: + */ + static int + pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, +- struct sshkey ***keysp, char ***labelsp, int *nkeys) ++ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) + { + struct sshkey *key = NULL; + CK_OBJECT_CLASS key_class; +- CK_ATTRIBUTE key_attr[2]; ++ CK_ATTRIBUTE key_attr[3]; ++ int nattr = 1; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1553,10 +1717,23 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, + key_attr[0].pValue = &key_class; + key_attr[0].ulValueLen = sizeof(key_class); + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ if (uri->id != NULL) { ++ key_attr[nattr].type = CKA_ID; ++ key_attr[nattr].pValue = uri->id; ++ key_attr[nattr].ulValueLen = uri->id_len; ++ nattr++; ++ } ++ if (uri->object != NULL) { ++ key_attr[nattr].type = CKA_LABEL; ++ key_attr[nattr].pValue = uri->object; ++ key_attr[nattr].ulValueLen = strlen(uri->object); ++ nattr++; ++ } ++ ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + +- rv = f->C_FindObjectsInit(session, key_attr, 1); ++ rv = f->C_FindObjectsInit(session, key_attr, nattr); + if (rv != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + goto fail; +@@ -1844,16 +2021,10 @@ pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx, + } + #endif /* WITH_PKCS11_KEYGEN */ + +-/* +- * register a new provider, fails if provider already exists. if +- * keyp is provided, fetch keys. +- */ + static int +-pkcs11_register_provider(char *provider_id, char *pin, +- struct sshkey ***keyp, char ***labelsp, +- struct pkcs11_provider **providerp, CK_ULONG user) ++pkcs11_initialize_provider(struct pkcs11_uri *uri, struct pkcs11_provider **providerp) + { +- int nkeys, need_finalize = 0; ++ int need_finalize = 0; + int ret = -1; + struct pkcs11_provider *p = NULL; + void *handle = NULL; +@@ -1862,128 +2033,126 @@ pkcs11_register_provider(char *provider_id, char *pin, + CK_FUNCTION_LIST *f = NULL; + CK_TOKEN_INFO *token; + CK_ULONG i; ++ char *provider_module = NULL; ++ struct pkcs11_module *m = NULL; ++ ++ /* if no provider specified, fallback to p11-kit */ ++ if (uri->module_path == NULL) { ++#ifdef PKCS11_DEFAULT_PROVIDER ++ provider_module = strdup(PKCS11_DEFAULT_PROVIDER); ++#else ++ error_f("No module path provided"); ++ goto fail; ++#endif ++ } else { ++ provider_module = strdup(uri->module_path); ++ } ++ p = xcalloc(1, sizeof(*p)); ++ p->name = pkcs11_uri_get(uri); + +- if (providerp == NULL) +- goto fail; +- *providerp = NULL; +- +- if (keyp != NULL) +- *keyp = NULL; +- if (labelsp != NULL) +- *labelsp = NULL; +- +- if (pkcs11_provider_lookup(provider_id) != NULL) { +- debug_f("provider already registered: %s", provider_id); ++ if (lib_contains_symbol(provider_module, "C_GetFunctionList") != 0) { ++ error("provider %s is not a PKCS11 library", provider_module); + goto fail; + } +- if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) { +- error("provider %s is not a PKCS11 library", provider_id); +- goto fail; ++ if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL ++ && m->valid) { ++ debug_f("provider module already initialized: %s", provider_module); ++ free(provider_module); ++ /* Skip the initialization of PKCS#11 module */ ++ m->refcount++; ++ p->module = m; ++ p->valid = 1; ++ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); ++ p->refcount++; /* add to provider list */ ++ *providerp = p; ++ return 0; ++ } else { ++ m = xcalloc(1, sizeof(*m)); ++ p->module = m; ++ m->refcount++; + } ++ + /* open shared pkcs11-library */ +- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { +- error("dlopen %s failed: %s", provider_id, dlerror()); ++ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) { ++ error("dlopen %s failed: %s", provider_module, dlerror()); + goto fail; + } + if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) + fatal("dlsym(C_GetFunctionList) failed: %s", dlerror()); +- p = xcalloc(1, sizeof(*p)); +- p->name = xstrdup(provider_id); +- p->handle = handle; ++ p->module->handle = handle; + /* setup the pkcs11 callbacks */ + if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { + error("C_GetFunctionList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- p->function_list = f; ++ m->function_list = f; + if ((rv = f->C_Initialize(NULL)) != CKR_OK) { + error("C_Initialize for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } + need_finalize = 1; +- if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { ++ if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) { + error("C_GetInfo for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d" +- " libraryDescription <%.*s> libraryVersion %d.%d", +- provider_id, +- RMSPACE(p->info.manufacturerID), +- p->info.cryptokiVersion.major, +- p->info.cryptokiVersion.minor, +- RMSPACE(p->info.libraryDescription), +- p->info.libraryVersion.major, +- p->info.libraryVersion.minor); +- if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { ++ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); ++ if (uri->lib_manuf != NULL && ++ strncmp(uri->lib_manuf, m->info.manufacturerID, 32)) { ++ debug_f("Skipping provider %s not matching library_manufacturer", ++ m->info.manufacturerID); ++ goto fail; ++ } ++ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); ++ debug("provider %s: manufacturerID <%.32s> cryptokiVersion %d.%d" ++ " libraryDescription <%.32s> libraryVersion %d.%d", ++ provider_module, ++ m->info.manufacturerID, ++ m->info.cryptokiVersion.major, ++ m->info.cryptokiVersion.minor, ++ m->info.libraryDescription, ++ m->info.libraryVersion.major, ++ m->info.libraryVersion.minor); ++ ++ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { + error("C_GetSlotList failed: %lu", rv); + goto fail; + } +- if (p->nslots == 0) { +- debug_f("provider %s returned no slots", provider_id); ++ if (m->nslots == 0) { ++ debug_f("provider %s returned no slots", provider_module); + ret = -SSH_PKCS11_ERR_NO_SLOTS; + goto fail; + } +- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); +- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) ++ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); ++ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) + != CKR_OK) { + error("C_GetSlotList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); ++ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); + p->valid = 1; +- nkeys = 0; +- for (i = 0; i < p->nslots; i++) { +- token = &p->slotinfo[i].token; +- if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) ++ m->valid = 1; ++ for (i = 0; i < m->nslots; i++) { ++ token = &m->slotinfo[i].token; ++ if ((rv = f->C_GetTokenInfo(m->slotlist[i], token)) + != CKR_OK) { + error("C_GetTokenInfo for provider %s slot %lu " +- "failed: %lu", provider_id, (u_long)i, rv); +- continue; +- } +- if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { +- debug2_f("ignoring uninitialised token in " +- "provider %s slot %lu", provider_id, (u_long)i); ++ "failed: %lu", provider_module, (u_long)i, rv); + continue; + } + debug("provider %s slot %lu: label <%.*s> " + "manufacturerID <%.*s> model <%.*s> serial <%.*s> " + "flags 0x%lx", +- provider_id, (unsigned long)i, ++ provider_module, (unsigned long)i, + RMSPACE(token->label), RMSPACE(token->manufacturerID), + RMSPACE(token->model), RMSPACE(token->serialNumber), + token->flags); +- /* +- * open session, login with pin and retrieve public +- * keys (if keyp is provided) +- */ +- if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 || +- keyp == NULL) +- continue; +- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +-#ifdef WITH_OPENSSL +- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); +-#endif +- if (nkeys == 0 && !p->slotinfo[i].logged_in && +- pkcs11_interactive) { +- /* +- * Some tokens require login before they will +- * expose keys. +- */ +- if (pkcs11_login_slot(p, &p->slotinfo[i], +- CKU_USER) < 0) { +- error("login failed"); +- continue; +- } +- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +-#ifdef WITH_OPENSSL +- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); +-#endif +- } + } ++ m->module_path = provider_module; ++ provider_module = NULL; + + /* now owned by caller */ + *providerp = p; +@@ -1991,21 +2160,22 @@ pkcs11_register_provider(char *provider_id, char *pin, + TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); + p->refcount++; /* add to provider list */ + +- return (nkeys); ++ return 0; + fail: + if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); ++ free(provider_module); ++ if (m) { ++ free(m->slotlist); ++ free(m); ++ } + if (p) { + free(p->name); +- free(p->slotlist); +- free(p->slotinfo); + free(p); + } + if (handle) + dlclose(handle); +- if (ret > 0) +- ret = -1; + return (ret); + } + +@@ -2041,18 +2211,161 @@ pkcs11_terminate(void) + } + + /* +- * register a new provider and get number of keys hold by the token, +- * fails if provider already exists ++ * register a new provider, fails if provider already exists. if ++ * keyp is provided, fetch keys. + */ ++static int ++pkcs11_register_provider_by_uri(struct pkcs11_uri *uri, char *pin, ++ struct sshkey ***keyp, char ***labelsp, struct pkcs11_provider **providerp, ++ CK_ULONG user) ++{ ++ int nkeys; ++ int ret = -1; ++ struct pkcs11_provider *p = NULL; ++ CK_ULONG i; ++ CK_TOKEN_INFO *token; ++ char *provider_uri = NULL; ++ ++ if (providerp == NULL) ++ goto fail; ++ *providerp = NULL; ++ ++ if (keyp != NULL) ++ *keyp = NULL; ++ ++ if ((ret = pkcs11_initialize_provider(uri, &p)) != 0) { ++ goto fail; ++ } ++ ++ provider_uri = pkcs11_uri_get(uri); ++ if (pin == NULL && uri->pin != NULL) { ++ pin = uri->pin; ++ } ++ nkeys = 0; ++ for (i = 0; i < p->module->nslots; i++) { ++ token = &p->module->slotinfo[i].token; ++ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { ++ debug2_f("ignoring uninitialised token in " ++ "provider %s slot %lu", provider_uri, (u_long)i); ++ continue; ++ } ++ if (uri->token != NULL && ++ strncmp(token->label, uri->token, 32) != 0) { ++ debug2_f("ignoring token not matching label (%.32s) " ++ "specified by PKCS#11 URI in slot %lu", ++ token->label, (unsigned long)i); ++ continue; ++ } ++ if (uri->manuf != NULL && ++ strncmp(token->manufacturerID, uri->manuf, 32) != 0) { ++ debug2_f("ignoring token not matching requrested " ++ "manufacturerID (%.32s) specified by PKCS#11 URI in " ++ "slot %lu", token->manufacturerID, (unsigned long)i); ++ continue; ++ } ++ if (uri->serial != NULL && ++ strncmp(token->serialNumber, uri->serial, 16) != 0) { ++ debug2_f("ignoring token not matching requrested " ++ "serialNumber (%s) specified by PKCS#11 URI in " ++ "slot %lu", token->serialNumber, (unsigned long)i); ++ continue; ++ } ++ debug("provider %s slot %lu: label <%.32s> manufacturerID <%.32s> " ++ "model <%.16s> serial <%.16s> flags 0x%lx", ++ provider_uri, (unsigned long)i, ++ token->label, token->manufacturerID, token->model, ++ token->serialNumber, token->flags); ++ /* ++ * open session if not yet opened, login with pin and ++ * retrieve public keys (if keyp is provided) ++ */ ++ if ((p->module->slotinfo[i].session != 0 || ++ (ret = pkcs11_open_session(p, i, pin, user)) != 0) && /* ??? */ ++ keyp == NULL) ++ continue; ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ if (nkeys == 0 && !p->module->slotinfo[i].logged_in && ++ pkcs11_interactive) { ++ /* ++ * Some tokens require login before they will ++ * expose keys. ++ */ ++ debug3_f("Trying to login as there were no keys found"); ++ if (pkcs11_login_slot(p, &p->module->slotinfo[i], ++ CKU_USER) < 0) { ++ error("login failed"); ++ continue; ++ } ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ } ++ if (nkeys == 0 && uri->object != NULL) { ++ debug3_f("No keys found. Retrying without label (%.32s) ", ++ uri->object); ++ /* Try once more without the label filter */ ++ char *label = uri->object; ++ uri->object = NULL; /* XXX clone uri? */ ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ uri->object = label; ++ } ++ } ++ pin = NULL; /* Will be cleaned up with URI */ ++ ++ /* now owned by caller */ ++ *providerp = p; ++ ++ free(provider_uri); ++ return (nkeys); ++ fail: ++ if (p) { ++ TAILQ_REMOVE(&pkcs11_providers, p, next); ++ pkcs11_provider_unref(p); ++ } ++ if (ret > 0) ++ ret = -1; ++ return (ret); ++} ++ ++static int ++pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp, ++ char ***labelsp, struct pkcs11_provider **providerp, CK_ULONG user) ++{ ++ struct pkcs11_uri *uri = NULL; ++ int r; ++ ++ debug_f("called, provider_id = %s", provider_id); ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ r = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, providerp, user); ++ pkcs11_uri_cleanup(uri); ++ ++ return r; ++} ++ + int +-pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, +- char ***labelsp) ++pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, ++ struct sshkey ***keyp, char ***labelsp) + { + struct pkcs11_provider *p = NULL; + int nkeys; ++ char *provider_uri = pkcs11_uri_get(uri); ++ ++ debug_f("called, provider_uri = %s", provider_uri); + +- nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp, +- &p, CKU_USER); ++ nkeys = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, &p, CKU_USER); + + /* no keys found or some other error, de-register provider */ + if (nkeys <= 0 && p != NULL) { +@@ -2061,11 +2374,38 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, + pkcs11_provider_unref(p); + } + if (nkeys == 0) +- debug_f("provider %s returned no keys", provider_id); ++ debug_f("provider %s returned no keys", provider_uri); + ++ free(provider_uri); + return (nkeys); + } + ++int ++pkcs11_add_provider(char *provider_id, char *pin, ++ struct sshkey ***keyp, char ***labelsp) ++{ ++ struct pkcs11_uri *uri; ++ int nkeys; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ nkeys = pkcs11_add_provider_by_uri(uri, pin, keyp, labelsp); ++ pkcs11_uri_cleanup(uri); ++ ++ return (nkeys); ++} ++ ++ + int + pkcs11_sign(struct sshkey *key, + u_char **sigp, size_t *lenp, +diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h +index d86c506c1..32f2d0ccf 100644 +--- a/ssh-pkcs11.h ++++ b/ssh-pkcs11.h +@@ -22,12 +22,16 @@ + #define SSH_PKCS11_ERR_PIN_REQUIRED 4 + #define SSH_PKCS11_ERR_PIN_LOCKED 5 + ++#include "ssh-pkcs11-uri.h" ++ + struct sshkey; + + int pkcs11_init(int); + void pkcs11_terminate(void); + int pkcs11_add_provider(char *, char *, struct sshkey ***, char ***); ++int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***, char ***); + int pkcs11_del_provider(char *); ++int pkcs11_uri_write(const struct sshkey *, FILE *); + int pkcs11_sign(struct sshkey *, u_char **, size_t *, + const u_char *, size_t, const char *, const char *, + const char *, u_int); +diff --git a/ssh.c b/ssh.c +index 320ac6834..14965a4f1 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -904,6 +904,14 @@ main(int ac, char **av) + options.gss_deleg_creds = 1; + break; + case 'i': ++#ifdef ENABLE_PKCS11 ++ if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(optarg, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ add_identity_file(&options, NULL, optarg, 1); ++ break; ++ } ++#endif + p = tilde_expand_filename(optarg, getuid()); + if (stat(p, &st) == -1) + fprintf(stderr, "Warning: Identity file %s " +@@ -1872,6 +1880,7 @@ main(int ac, char **av) + #ifdef ENABLE_PKCS11 + (void)pkcs11_del_provider(options.pkcs11_provider); + #endif ++ pkcs11_terminate(); + + skip_connect: + if (addrs != NULL) +@@ -2387,6 +2396,45 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) + options.escape_char : SSH_ESCAPECHAR_NONE, id); + } + ++#ifdef ENABLE_PKCS11 ++static void ++load_pkcs11_identity(char *pkcs11_uri, char *identity_files[], ++ struct sshkey *identity_keys[], int *n_ids) ++{ ++ int nkeys, i; ++ struct sshkey **keys; ++ struct pkcs11_uri *uri; ++ ++ debug("identity file '%s' from pkcs#11", pkcs11_uri); ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (pkcs11_uri_parse(pkcs11_uri, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri); ++ ++ /* we need to merge URI and provider together */ ++ if (options.pkcs11_provider != NULL && uri->module_path == NULL) ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES && ++ (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys, NULL)) > 0) { ++ for (i = 0; i < nkeys; i++) { ++ if (*n_ids >= SSH_MAX_IDENTITY_FILES) { ++ sshkey_free(keys[i]); ++ continue; ++ } ++ identity_keys[*n_ids] = keys[i]; ++ identity_files[*n_ids] = pkcs11_uri_get(uri); ++ (*n_ids)++; ++ } ++ free(keys); ++ } ++ ++ pkcs11_uri_cleanup(uri); ++} ++#endif /* ENABLE_PKCS11 */ ++ + /* Loads all IdentityFile and CertificateFile keys */ + static void + load_public_identity_files(const struct ssh_conn_info *cinfo) +@@ -2401,11 +2449,6 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) + char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; + struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; + int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; +-#ifdef ENABLE_PKCS11 +- struct sshkey **keys = NULL; +- char **comments = NULL; +- int nkeys; +-#endif /* PKCS11 */ + + n_ids = n_certs = 0; + memset(identity_files, 0, sizeof(identity_files)); +@@ -2418,33 +2461,46 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) + sizeof(certificate_file_userprovided)); + + #ifdef ENABLE_PKCS11 +- if (options.pkcs11_provider != NULL && +- options.num_identity_files < SSH_MAX_IDENTITY_FILES && +- (pkcs11_init(!options.batch_mode) == 0) && +- (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, +- &keys, &comments)) > 0) { +- for (i = 0; i < nkeys; i++) { +- if (n_ids >= SSH_MAX_IDENTITY_FILES) { +- sshkey_free(keys[i]); +- free(comments[i]); +- continue; +- } +- identity_keys[n_ids] = keys[i]; +- identity_files[n_ids] = comments[i]; /* transferred */ +- n_ids++; +- } +- free(keys); +- free(comments); ++ /* handle fallback from PKCS11Provider option */ ++ pkcs11_init(!options.batch_mode); ++ ++ if (options.pkcs11_provider != NULL) { ++ struct pkcs11_uri *uri; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ /* Construct simple PKCS#11 URI to simplify access */ ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ /* Add it as any other IdentityFile */ ++ cp = pkcs11_uri_get(uri); ++ add_identity_file(&options, NULL, cp, 1); ++ free(cp); ++ ++ pkcs11_uri_cleanup(uri); + } + #endif /* ENABLE_PKCS11 */ + for (i = 0; i < options.num_identity_files; i++) { ++ char *name = options.identity_files[i]; + if (n_ids >= SSH_MAX_IDENTITY_FILES || +- strcasecmp(options.identity_files[i], "none") == 0) { ++ strcasecmp(name, "none") == 0) { + free(options.identity_files[i]); + options.identity_files[i] = NULL; + continue; + } +- cp = tilde_expand_filename(options.identity_files[i], getuid()); ++#ifdef ENABLE_PKCS11 ++ if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(name, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ load_pkcs11_identity(name, identity_files, ++ identity_keys, &n_ids); ++ free(options.identity_files[i]); ++ continue; ++ } ++#endif /* ENABLE_PKCS11 */ ++ cp = tilde_expand_filename(name, getuid()); + filename = default_client_percent_dollar_expand(cp, cinfo); + free(cp); + check_load(sshkey_load_public(filename, &public, NULL), +diff --git a/ssh_config.5 b/ssh_config.5 +index a06fbfa11..717b0938a 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -1260,6 +1260,21 @@ may also be used in conjunction with + .Cm CertificateFile + in order to provide any certificate also needed for authentication with + the identity. ++.Pp ++The authentication identity can be also specified in a form of PKCS#11 URI ++starting with a string ++.Cm pkcs11: . ++There is supported a subset of the PKCS#11 URI as defined ++in RFC 7512 (implemented path arguments ++.Cm id , ++.Cm manufacturer , ++.Cm object , ++.Cm token ++and query arguments ++.Cm module-path ++and ++.Cm pin-value ++). The URI can not be in quotes. + .It Cm IgnoreUnknown + Specifies a pattern-list of unknown options to be ignored if they are + encountered in configuration parsing. +-- +2.52.0 + diff --git a/1000-openssh-6.7p1-coverity.patch b/1000-openssh-6.7p1-coverity.patch new file mode 100644 index 0000000..40c298e --- /dev/null +++ b/1000-openssh-6.7p1-coverity.patch @@ -0,0 +1,229 @@ +From aecc5861e1cf7094a32f893ae4bfd8409b77e5cd Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Fri, 12 Dec 2025 14:25:41 +0100 +Subject: [PATCH 53/53] openssh-6.7p1-coverity + +--- + auth-krb5.c | 2 ++ + gss-genr.c | 3 ++- + krl.c | 3 +++ + loginrec.c | 2 ++ + misc.c | 3 +++ + monitor.c | 4 ++-- + openbsd-compat/bindresvport.c | 2 +- + openbsd-compat/bsd-pselect.c | 8 ++++---- + readconf.c | 1 + + servconf.c | 5 +++-- + serverloop.c | 2 +- + 11 files changed, 24 insertions(+), 11 deletions(-) + +diff --git a/auth-krb5.c b/auth-krb5.c +index b9c261a24..a37be93c3 100644 +--- a/auth-krb5.c ++++ b/auth-krb5.c +@@ -427,6 +427,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(oerrno)); ++ free(ccname); + return oerrno; + } + +@@ -434,6 +435,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm + oerrno = errno; + logit("fchmod(): %.100s", strerror(oerrno)); + close(tmpfd); ++ free(ccname); + return oerrno; + } + /* make sure the KRB5CCNAME is set for non-standard location */ +diff --git a/gss-genr.c b/gss-genr.c +index f2d6f59e5..91602e045 100644 +--- a/gss-genr.c ++++ b/gss-genr.c +@@ -178,8 +178,9 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, + enclen = __b64_ntop(digest, + ssh_digest_bytes(SSH_DIGEST_MD5), encoded, + ssh_digest_bytes(SSH_DIGEST_MD5) * 2); +- ++#pragma GCC diagnostic ignored "-Wstringop-overflow" + cp = strncpy(s, kex, strlen(kex)); ++#pragma GCC diagnostic pop + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (sshbuf_len(buf) != 0 && +diff --git a/krl.c b/krl.c +index bea5b1b98..4dd8a24a9 100644 +--- a/krl.c ++++ b/krl.c +@@ -1205,6 +1205,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by key SHA1")); + return SSH_ERR_KEY_REVOKED; +@@ -1215,6 +1216,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by key SHA256")); + return SSH_ERR_KEY_REVOKED; +@@ -1226,6 +1228,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by explicit key")); + return SSH_ERR_KEY_REVOKED; +diff --git a/loginrec.c b/loginrec.c +index 7d1c9dd43..a017e173b 100644 +--- a/loginrec.c ++++ b/loginrec.c +@@ -677,9 +677,11 @@ construct_utmp(struct logininfo *li, + */ + + /* Use strncpy because we don't necessarily want null termination */ ++ /* coverity[buffer_size_warning : FALSE] */ + strncpy(ut->ut_name, li->username, + MIN_SIZEOF(ut->ut_name, li->username)); + # ifdef HAVE_HOST_IN_UTMP ++ /* coverity[buffer_size_warning : FALSE] */ + strncpy(ut->ut_host, li->hostname, + MIN_SIZEOF(ut->ut_host, li->hostname)); + # endif +diff --git a/misc.c b/misc.c +index 2fd14159d..d4c4e4164 100644 +--- a/misc.c ++++ b/misc.c +@@ -1573,6 +1573,8 @@ sanitise_stdfd(void) + } + if (nullfd > STDERR_FILENO) + close(nullfd); ++ /* coverity[leaked_handle : FALSE]*/ ++ /* coverity[leaked_handle : FALSE]*/ + } + + char * +@@ -2773,6 +2775,7 @@ stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) + } + if (devnull > STDERR_FILENO) + close(devnull); ++ /* coverity[leaked_handle : FALSE]*/ + return ret; + } + +diff --git a/monitor.c b/monitor.c +index 2f154a3d7..f959e0124 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -405,7 +405,7 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) + mm_get_keystate(ssh, pmonitor); + + /* Drain any buffered messages from the child */ +- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) + ; + + /* Wait for the child's exit status */ +@@ -1819,7 +1819,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) + s->ptymaster = s->ptyfd; + + debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd); +- ++ /* coverity[leaked_handle : FALSE] */ + return (0); + + error: +diff --git a/openbsd-compat/bindresvport.c b/openbsd-compat/bindresvport.c +index 346c7fe56..f42792fde 100644 +--- a/openbsd-compat/bindresvport.c ++++ b/openbsd-compat/bindresvport.c +@@ -59,7 +59,7 @@ bindresvport_sa(int sd, struct sockaddr *sa) + struct sockaddr_in6 *in6; + u_int16_t *portp; + u_int16_t port; +- socklen_t salen; ++ socklen_t salen = sizeof(struct sockaddr_storage); + int i; + + if (sa == NULL) { +diff --git a/openbsd-compat/bsd-pselect.c b/openbsd-compat/bsd-pselect.c +index 26bdc3e08..8e2939b95 100644 +--- a/openbsd-compat/bsd-pselect.c ++++ b/openbsd-compat/bsd-pselect.c +@@ -85,13 +85,13 @@ pselect_notify_setup(void) + static void + pselect_notify_parent(void) + { +- if (notify_pipe[1] != -1) ++ if (notify_pipe[1] >= 0) + (void)write(notify_pipe[1], "", 1); + } + static void + pselect_notify_prepare(fd_set *readset) + { +- if (notify_pipe[0] != -1) ++ if (notify_pipe[0] >= 0) + FD_SET(notify_pipe[0], readset); + } + static void +@@ -99,8 +99,8 @@ pselect_notify_done(fd_set *readset) + { + char c; + +- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) { +- while (read(notify_pipe[0], &c, 1) != -1) ++ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) { ++ while (read(notify_pipe[0], &c, 1) >= 0) + debug2_f("reading"); + FD_CLR(notify_pipe[0], readset); + } +diff --git a/readconf.c b/readconf.c +index b6ad47b49..75e1c953c 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -2170,6 +2170,7 @@ parse_pubkey_algos: + } else if (r != 0) { + error("%.200s line %d: glob failed for %s.", + filename, linenum, arg2); ++ free(arg2); + goto out; + } + free(arg2); +diff --git a/servconf.c b/servconf.c +index 956205f6d..1093dcbac 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -2307,8 +2307,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, + if (*activep && *charptr == NULL) { + *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ +- if (intptr != NULL) +- *intptr = *intptr + 1; ++ /* DEAD CODE intptr is still NULL ;) ++ if (intptr != NULL) ++ *intptr = *intptr + 1; */ + } + break; + +diff --git a/serverloop.c b/serverloop.c +index 55411a6b4..acc721cd1 100644 +--- a/serverloop.c ++++ b/serverloop.c +@@ -533,7 +533,7 @@ server_request_tun(struct ssh *ssh) + debug_f("invalid tun"); + goto done; + } +- if (auth_opts->force_tun_device != -1) { ++ if (auth_opts->force_tun_device >= 0) { + if (tun != SSH_TUNID_ANY && + auth_opts->force_tun_device != (int)tun) + goto done; +-- +2.52.0 + diff --git a/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.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch deleted file mode 100644 index fa9d591..0000000 --- a/openssh-6.6.1p1-selinux-contexts.patch +++ /dev/null @@ -1,133 +0,0 @@ -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index 8f32464..18a2ca4 100644 ---- a/openbsd-compat/port-linux-sshd.c -+++ b/openbsd-compat/port-linux-sshd.c -@@ -32,6 +32,7 @@ - #include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ - #include "servconf.h" - #include "port-linux.h" -+#include "misc.h" - #include "sshkey.h" - #include "hostfile.h" - #include "auth.h" -@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname) - void - sshd_selinux_copy_context(void) - { -- security_context_t *ctx; -+ char *ctx; - - if (!sshd_selinux_enabled()) - return; -@@ -461,6 +462,72 @@ sshd_selinux_copy_context(void) - } - } - -+void -+sshd_selinux_change_privsep_preauth_context(void) -+{ -+ int len; -+ char line[1024], *preauth_context = NULL, *cp, *arg; -+ const char *contexts_path; -+ FILE *contexts_file; -+ struct stat sb; -+ -+ contexts_path = selinux_openssh_contexts_path(); -+ if (contexts_path == NULL) { -+ debug3_f("Failed to get the path to SELinux context"); -+ return; -+ } -+ -+ if ((contexts_file = fopen(contexts_path, "r")) == NULL) { -+ debug_f("Failed to open SELinux context file"); -+ return; -+ } -+ -+ if (fstat(fileno(contexts_file), &sb) != 0 || -+ sb.st_uid != 0 || (sb.st_mode & 022) != 0) { -+ logit_f("SELinux context file needs to be owned by root" -+ " and not writable by anyone else"); -+ fclose(contexts_file); -+ return; -+ } -+ -+ while (fgets(line, sizeof(line), contexts_file)) { -+ /* Strip trailing whitespace */ -+ for (len = strlen(line) - 1; len > 0; len--) { -+ if (strchr(" \t\r\n", line[len]) == NULL) -+ break; -+ line[len] = '\0'; -+ } -+ -+ if (line[0] == '\0') -+ continue; -+ -+ cp = line; -+ arg = strdelim(&cp); -+ if (arg && *arg == '\0') -+ arg = strdelim(&cp); -+ -+ if (arg && strcmp(arg, "privsep_preauth") == 0) { -+ arg = strdelim(&cp); -+ if (!arg || *arg == '\0') { -+ debug_f("privsep_preauth is empty"); -+ fclose(contexts_file); -+ return; -+ } -+ preauth_context = xstrdup(arg); -+ } -+ } -+ fclose(contexts_file); -+ -+ if (preauth_context == NULL) { -+ debug_f("Unable to find 'privsep_preauth' option in" -+ " SELinux context file"); -+ return; -+ } -+ -+ ssh_selinux_change_context(preauth_context); -+ free(preauth_context); -+} -+ - #endif - #endif - -diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index 22ea8ef..1fc963d 100644 ---- a/openbsd-compat/port-linux.c -+++ b/openbsd-compat/port-linux.c -@@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) - strlcpy(newctx + len, newname, newlen - len); - if ((cx = index(cx + 1, ':'))) - strlcat(newctx, cx, newlen); -- debug3("%s: setting context from '%s' to '%s'", __func__, -+ debug_f("setting context from '%s' to '%s'", - oldctx, newctx); - if (setcon(newctx) < 0) - do_log2(log_level, "%s: setcon %s from %s failed with %s", - __func__, newctx, oldctx, strerror(errno)); -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index cb51f99..8b7cda2 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -29,6 +29,7 @@ int sshd_selinux_enabled(void); - void sshd_selinux_copy_context(void); - void sshd_selinux_setup_exec_context(char *); - int sshd_selinux_setup_env_variables(void); -+void sshd_selinux_change_privsep_preauth_context(void); - #endif - - #ifdef LINUX_OOM_ADJUST -diff --git a/sshd.c b/sshd.c -index 2871fe9..39b9c08 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -629,7 +629,7 @@ privsep_preauth_child(void) - demote_sensitive_data(); - - #ifdef WITH_SELINUX -- ssh_selinux_change_context("sshd_net_t"); -+ sshd_selinux_change_privsep_preauth_context(); - #endif - - /* Demote the child */ diff --git a/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 1dca99c..0000000 --- a/openssh-6.7p1-coverity.patch +++ /dev/null @@ -1,351 +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/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.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 95d86c3..0000000 --- a/openssh-9.3p1-merged-openssl-evp.patch +++ /dev/null @@ -1,1236 +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 - -@@ -44,6 +44,9 @@ - #include "digest.h" - #define SSHKEY_INTERNAL - #include "sshkey.h" -+#ifdef ENABLE_PKCS11 -+#include "ssh-pkcs11.h" -+#endif - - #include "openbsd-compat/openssl-compat.h" - -@@ -126,19 +128,29 @@ - static int - ssh_ecdsa_generate(struct sshkey *k, int bits) - { -- EC_KEY *private; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *res = NULL; - - if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) - return SSH_ERR_KEY_LENGTH; -- if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL) -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) - return SSH_ERR_ALLOC_FAIL; -- if (EC_KEY_generate_key(private) != 1) { -- EC_KEY_free(private); -+ -+ if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(k->ecdsa_nid)) <= 0 -+ || EVP_PKEY_keygen(ctx, &res) <= 0) { -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); - return SSH_ERR_LIBCRYPTO_ERROR; - } -- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); -- k->ecdsa = private; -- return 0; -+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ -+ k->ecdsa = EVP_PKEY_get1_EC_KEY(res); -+ if (k->ecdsa) -+ EC_KEY_set_asn1_flag(k->ecdsa, OPENSSL_EC_NAMED_CURVE); -+ -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); -+ return (k->ecdsa) ? 0 : SSH_ERR_LIBCRYPTO_ERROR; - } - - static int -@@ -228,11 +240,13 @@ - const u_char *data, size_t dlen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *esig = NULL; -+ unsigned char *sigb = NULL; -+ const unsigned char *psig; - const BIGNUM *sig_r, *sig_s; - int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t len, hlen; -+ int len; - struct sshbuf *b = NULL, *bb = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - -@@ -245,18 +259,33 @@ - sshkey_type_plain(key->type) != KEY_ECDSA) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (hlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -+ -+#ifdef ENABLE_PKCS11 -+ if (is_ecdsa_pkcs11(key->ecdsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 -+ } -+#endif -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, -+ dlen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; -+ } - -- if ((esig = ECDSA_do_sign(digest, hlen, key->ecdsa)) == NULL) { -+ psig = sigb; -+ if (d2i_ECDSA_SIG(&esig, &psig, len) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- - if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; -@@ -280,7 +309,7 @@ - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(b); - sshbuf_free(bb); - ECDSA_SIG_free(esig); -@@ -293,22 +322,21 @@ - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *esig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; -- int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t hlen; -+ int hash_alg, len; - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL, *sigbuf = NULL; - char *ktype = NULL; -+ unsigned char *sigb = NULL, *psig = NULL; - - if (key == NULL || key->ecdsa == NULL || - sshkey_type_plain(key->type) != KEY_ECDSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (hlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ -@@ -344,28 +372,33 @@ - } - sig_r = sig_s = NULL; /* transferred */ - -- if (sshbuf_len(sigbuf) != 0) { -- ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; -+ /* Figure out the length */ -+ if ((len = i2d_ECDSA_SIG(esig, NULL)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -- goto out; -- -- switch (ECDSA_do_verify(digest, hlen, esig, key->ecdsa)) { -- case 1: -- ret = 0; -- break; -- case 0: -- ret = SSH_ERR_SIGNATURE_INVALID; -+ if ((sigb = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; -- default: -+ } -+ psig = sigb; -+ if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - -+ if (sshbuf_len(sigbuf) != 0) { -+ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; -+ goto out; -+ } -+ -+ if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) -+ goto out; -+ ret = sshkey_verify_signature(pkey, hash_alg, data, dlen, sigb, len); -+ EVP_PKEY_free(pkey); -+ - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(sigbuf); - sshbuf_free(b); - ECDSA_SIG_free(esig); -@@ -375,6 +408,79 @@ - return ret; - } - -+int -+ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ BN_CTX *bn_ctx = NULL; -+ uint8_t *pub_ser = NULL; -+ const char *group_name; -+ const EC_POINT *pub = NULL; -+ const BIGNUM *priv = NULL; -+ int ret = 0; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL || -+ (bn_ctx = BN_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, -+ group_name, -+ strlen(group_name)) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { -+ const EC_GROUP *group; -+ size_t len; -+ -+ group = EC_KEY_get0_group(k); -+ len = EC_POINT_point2oct(group, pub, -+ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); -+ if ((pub_ser = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ EC_POINT_point2oct(group, -+ pub, -+ POINT_CONVERSION_UNCOMPRESSED, -+ pub_ser, -+ len, -+ bn_ctx); -+ if (OSSL_PARAM_BLD_push_octet_string(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, -+ pub_ser, -+ len) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ } -+ if ((priv = EC_KEY_get0_private_key(k)) != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ BN_CTX_free(bn_ctx); -+ free(pub_ser); -+ return ret; -+} -+ - /* NB. not static; used by ECDSA-SK */ - const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { - /* .size = */ ssh_ecdsa_size, -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshkey.c openssh-9.3p1-patched/sshkey.c ---- openssh-9.3p1/sshkey.c 2023-06-06 15:53:36.608444190 +0200 -+++ openssh-9.3p1-patched/sshkey.c 2023-06-06 15:52:25.625551756 +0200 -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - #endif - - #include "crypto_api.h" -@@ -575,6 +577,86 @@ - } - - #ifdef WITH_OPENSSL -+int -+sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, -+ int *lenp, const u_char *data, size_t datalen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ u_char *sig = NULL; -+ int ret, slen; -+ size_t len; -+ -+ if (sigp == NULL || lenp == NULL) { -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ -+ slen = EVP_PKEY_get_size(pkey); -+ if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -+ return SSH_ERR_INVALID_ARGUMENT; -+ -+ len = slen; -+ if ((sig = malloc(slen)) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto error; -+ } -+ if (EVP_DigestSignInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestSignUpdate(ctx, data, datalen) != 1 || -+ EVP_DigestSignFinal(ctx, sig, &len) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto error; -+ } -+ -+ *sigp = sig; -+ *lenp = len; -+ /* Now owned by the caller */ -+ sig = NULL; -+ ret = 0; -+ -+error: -+ EVP_MD_CTX_free(ctx); -+ free(sig); -+ return ret; -+} -+ -+int -+sshkey_verify_signature(EVP_PKEY *pkey, int hash_alg, const u_char *data, -+ size_t datalen, u_char *sigbuf, int siglen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ int ret; -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ if (EVP_DigestVerifyInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestVerifyUpdate(ctx, data, datalen) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto done; -+ } -+ ret = EVP_DigestVerifyFinal(ctx, sigbuf, siglen); -+ switch (ret) { -+ case 1: -+ ret = 0; -+ break; -+ case 0: -+ ret = SSH_ERR_SIGNATURE_INVALID; -+ break; -+ default: -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ break; -+ } -+ -+done: -+ EVP_MD_CTX_free(ctx); -+ return ret; -+} -+ - /* XXX: these are really begging for a table-driven approach */ - int - sshkey_curve_name_to_nid(const char *name) -@@ -3763,3 +3845,27 @@ - return 0; - } - #endif /* WITH_XMSS */ -+ -+#ifdef WITH_OPENSSL -+EVP_PKEY * -+sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) -+{ -+ EVP_PKEY *ret = NULL; -+ OSSL_PARAM *params = NULL; -+ if (param_bld == NULL || ctx == NULL) { -+ debug2_f("param_bld or ctx is NULL"); -+ return NULL; -+ } -+ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ debug2_f("Could not build param list"); -+ return NULL; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1 || -+ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { -+ debug2_f("EVP_PKEY_fromdata failed"); -+ OSSL_PARAM_free(params); -+ return NULL; -+ } -+ return ret; -+} -+#endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshkey.h openssh-9.3p1-patched/sshkey.h ---- openssh-9.3p1/sshkey.h 2023-06-06 15:53:36.608444190 +0200 -+++ openssh-9.3p1-patched/sshkey.h 2023-06-06 15:52:25.626551768 +0200 -@@ -31,6 +31,9 @@ - #ifdef WITH_OPENSSL - #include - #include -+#include -+#include -+#include - # ifdef OPENSSL_HAS_ECC - # include - # include -@@ -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. Note, that this does NOT guarantee the buffer - * will be null terminated if there are no trailing spaces! */ - static void -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,10 +36,13 @@ - #include "sshkey.h" - #include "digest.h" - #include "log.h" -+#ifdef ENABLE_PKCS11 -+#include "ssh-pkcs11.h" -+#endif - - #include "openbsd-compat/openssl-compat.h" - --static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); -+static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); - - static u_int - ssh_rsa_size(const struct sshkey *key) -@@ -131,27 +133,50 @@ - static int - ssh_rsa_generate(struct sshkey *k, int bits) - { -- RSA *private = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *res = NULL; - BIGNUM *f4 = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - - if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE || - bits > SSHBUF_MAX_BIGNUM * 8) - return SSH_ERR_KEY_LENGTH; -- if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL -+ || (f4 = BN_new()) == NULL || !BN_set_word(f4, RSA_F4)) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (!BN_set_word(f4, RSA_F4) || -- !RSA_generate_key_ex(private, bits, f4, NULL)) { -+ -+ if (EVP_PKEY_keygen_init(ctx) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) { -+ ret = SSH_ERR_KEY_LENGTH; -+ goto out; -+ } -+ -+ if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, f4) <= 0) -+ goto out; -+ -+ if (EVP_PKEY_keygen(ctx, &res) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ -+ k->rsa = EVP_PKEY_get1_RSA(res); -+ if (k->rsa) { -+ ret = 0; -+ } else { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- k->rsa = private; -- private = NULL; -- ret = 0; - out: -- RSA_free(private); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); - BN_free(f4); - return ret; - } -@@ -317,21 +342,6 @@ - return -1; - } - --static int --rsa_hash_alg_nid(int type) --{ -- switch (type) { -- case SSH_DIGEST_SHA1: -- return NID_sha1; -- case SSH_DIGEST_SHA256: -- return NID_sha256; -- case SSH_DIGEST_SHA512: -- return NID_sha512; -- default: -- return -1; -- } --} -- - int - ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) - { -@@ -393,11 +403,10 @@ - const u_char *data, size_t datalen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) - { -- const BIGNUM *rsa_n; -- u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; -- size_t slen = 0; -- u_int hlen, len; -- int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; -+ EVP_PKEY *pkey = NULL; -+ u_char *sig = NULL; -+ int len, slen = 0; -+ int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - - if (lenp != NULL) -@@ -409,33 +418,33 @@ - hash_alg = SSH_DIGEST_SHA1; - else - hash_alg = rsa_hash_id_from_keyname(alg); -+ - if (key == NULL || key->rsa == NULL || hash_alg == -1 || - sshkey_type_plain(key->type) != KEY_RSA) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -- return SSH_ERR_KEY_LENGTH; - slen = RSA_size(key->rsa); -- if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -- return SSH_ERR_INVALID_ARGUMENT; -- -- /* hash the data */ -- nid = rsa_hash_alg_nid(hash_alg); -- if ((hlen = ssh_digest_bytes(hash_alg)) == 0) -- return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -- goto out; -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ return SSH_ERR_KEY_LENGTH; - -- if ((sig = malloc(slen)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto out; -+#ifdef ENABLE_PKCS11 -+ if (is_rsa_pkcs11(key->rsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 - } -- -- if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -+#endif -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, -+ datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; - } -+ - if (len < slen) { - size_t diff = slen - len; - memmove(sig + diff, sig, len); -@@ -444,6 +453,7 @@ - ret = SSH_ERR_INTERNAL_ERROR; - goto out; - } -+ - /* encode signature */ - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; -@@ -464,7 +474,6 @@ - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); - freezero(sig, slen); - sshbuf_free(b); - return ret; -@@ -476,10 +485,10 @@ - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) - { -- const BIGNUM *rsa_n; -+ EVP_PKEY *pkey = NULL; - char *sigtype = NULL; - int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; -- size_t len = 0, diff, modlen, hlen; -+ size_t len = 0, diff, modlen; - struct sshbuf *b = NULL; - u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; - -@@ -487,8 +496,7 @@ - sshkey_type_plain(key->type) != KEY_RSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; - - if ((b = sshbuf_from(sig, siglen)) == NULL) -@@ -540,16 +548,13 @@ - explicit_bzero(sigblob, diff); - len = modlen; - } -- if ((hlen = ssh_digest_bytes(hash_alg)) == 0) { -- ret = SSH_ERR_INTERNAL_ERROR; -- goto out; -- } -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -+ -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) - goto out; - -- ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len, -- key->rsa); -+ ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, pkey); -+ EVP_PKEY_free(pkey); -+ - out: - freezero(sigblob, len); - free(sigtype); -@@ -558,125 +563,110 @@ - return ret; - } - --/* -- * See: -- * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ -- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn -- */ -- --/* -- * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) -- * oiw(14) secsig(3) algorithms(2) 26 } -- */ --static const u_char id_sha1[] = { -- 0x30, 0x21, /* type Sequence, length 0x21 (33) */ -- 0x30, 0x09, /* type Sequence, length 0x09 */ -- 0x06, 0x05, /* type OID, length 0x05 */ -- 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(1) } -- */ --static const u_char id_sha256[] = { -- 0x30, 0x31, /* type Sequence, length 0x31 (49) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(3) } -- */ --static const u_char id_sha512[] = { -- 0x30, 0x51, /* type Sequence, length 0x51 (81) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ --}; -- - static int --rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) -+openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, -+ u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) - { -- switch (hash_alg) { -- case SSH_DIGEST_SHA1: -- *oidp = id_sha1; -- *oidlenp = sizeof(id_sha1); -- break; -- case SSH_DIGEST_SHA256: -- *oidp = id_sha256; -- *oidlenp = sizeof(id_sha256); -- break; -- case SSH_DIGEST_SHA512: -- *oidp = id_sha512; -- *oidlenp = sizeof(id_sha512); -- break; -- default: -- return SSH_ERR_INVALID_ARGUMENT; -- } -- return 0; --} -+ size_t rsasize = 0; -+ int ret; - --static int --openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, -- u_char *sigbuf, size_t siglen, RSA *rsa) --{ -- size_t rsasize = 0, oidlen = 0, hlen = 0; -- int ret, len, oidmatch, hashmatch; -- const u_char *oid = NULL; -- u_char *decrypted = NULL; -- -- if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) -- return ret; -- ret = SSH_ERR_INTERNAL_ERROR; -- hlen = ssh_digest_bytes(hash_alg); -- if (hashlen != hlen) { -- ret = SSH_ERR_INVALID_ARGUMENT; -- goto done; -- } -- rsasize = RSA_size(rsa); -+ rsasize = EVP_PKEY_get_size(pkey); - if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || - siglen == 0 || siglen > rsasize) { - ret = SSH_ERR_INVALID_ARGUMENT; - goto done; - } -- if ((decrypted = malloc(rsasize)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto done; -- } -- if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, -- RSA_PKCS1_PADDING)) < 0) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -- goto done; -- } -- if (len < 0 || (size_t)len != hlen + oidlen) { -- ret = SSH_ERR_INVALID_FORMAT; -- goto done; -- } -- oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; -- hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; -- if (!oidmatch || !hashmatch) { -- ret = SSH_ERR_SIGNATURE_INVALID; -- goto done; -- } -- ret = 0; -+ -+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, -+ sigbuf, siglen); -+ - done: -- freezero(decrypted, rsasize); - return ret; - } - -+int -+ssh_create_evp_rsa(const struct sshkey *k, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ int ret = 0; -+ const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; -+ const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ RSA_get0_key(k->rsa, &n, &e, &d); -+ RSA_get0_factors(k->rsa, &p, &q); -+ RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); -+ -+ if (n != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, n) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (e != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (d != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* setting this to param_build makes the creation process fail */ -+ if (p != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1) { -+ debug2_f("failed to add 'p' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (q != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1) { -+ debug2_f("failed to add 'q' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmp1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1) { -+ debug2_f("failed to add 'dmp1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmq1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1) { -+ debug2_f("failed to add 'dmq1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (iqmp != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { -+ debug2_f("failed to add 'iqmp' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return ret; -+} -+ - static const struct sshkey_impl_funcs sshkey_rsa_funcs = { - /* .size = */ ssh_rsa_size, - /* .alloc = */ ssh_rsa_alloc, diff --git a/openssh-9.3p1-openssl-compat.patch b/openssh-9.3p1-openssl-compat.patch 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.rpmlintrc b/openssh.rpmlintrc index 2404235..7031b2b 100644 --- a/openssh.rpmlintrc +++ b/openssh.rpmlintrc @@ -2,9 +2,7 @@ addFilter(r'openssh-askpass.x86_64: W: non-conffile-in-etc /etc/profile.d/gnome-ssh-askpass.c?sh') # The ssh-keysign is not supposed to have standard permissions -addFilter(r'openssh.x86_64: E: non-standard-executable-perm /usr/libexec/openssh/ssh-keysign 2555') -addFilter(r'openssh.x86_64: E: setgid-binary /usr/libexec/openssh/ssh-keysign ssh_keys 2555') -addFilter(r'openssh.x86_64: W: non-standard-gid /usr/libexec/openssh/ssh-keysign ssh_keys') +addFilter(r'openssh.x86_64: E: non-standard-executable-perm /usr/libexec/openssh/ssh-keysign 4555') # The -cavs subpackage is internal without documentation # The -askpass is not intended to be used directly so it is missing documentation diff --git a/openssh.spec b/openssh.spec index 3076ac0..ff38f4b 100644 --- a/openssh.spec +++ b/openssh.spec @@ -25,13 +25,6 @@ # Do we want libedit support %global libedit 1 -# Whether to build pam_ssh_agent_auth -%if 0%{?!nopam:1} -%global pam_ssh_agent 1 -%else -%global pam_ssh_agent 0 -%endif - # Reserve options to override askpass settings with: # rpm -ba|--rebuild --define 'skip_xxx 1' %{?skip_gnome_askpass:%global no_gnome_askpass 1} @@ -45,24 +38,17 @@ # rpm -ba|--rebuild --define "static_openssl 1" %{?static_openssl:%global static_libcrypto 1} -# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%global openssh_ver 9.3p1 -%global openssh_rel 13 -%global pam_ssh_agent_ver 0.10.4 -%global pam_ssh_agent_rel 9 +%global openssh_ver 10.2p1 Summary: An open source implementation of SSH protocol version 2 Name: openssh Version: %{openssh_ver} -Release: %{openssh_rel}%{?dist}.1 +Release: 1%{?dist} URL: http://www.openssh.com/portable.html -#URL1: https://github.com/jbeverly/pam_ssh_agent_auth/ Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc Source2: sshd.pam Source3: gpgkey-736060BA.gpg -Source4: https://github.com/jbeverly/pam_ssh_agent_auth/archive/pam_ssh_agent_auth-%{pam_ssh_agent_ver}.tar.gz -Source5: pam_ssh_agent-rmheaders Source6: ssh-keycat.pam Source7: sshd.sysconfig Source9: sshd@.service @@ -76,164 +62,123 @@ Source17: ssh-agent.socket Source19: openssh-server-systemd-sysusers.conf Source20: ssh-host-keys-migration.sh Source21: ssh-host-keys-migration.service - -#https://bugzilla.mindrot.org/show_bug.cgi?id=2581 -Patch100: openssh-6.7p1-coverity.patch - -#https://bugzilla.mindrot.org/show_bug.cgi?id=1402 -# https://bugzilla.redhat.com/show_bug.cgi?id=1171248 -# record pfs= field in CRYPTO_SESSION audit event -Patch200: openssh-7.6p1-audit.patch -# Audit race condition in forked child (#1310684) -Patch201: openssh-7.1p2-audit-race-condition.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=2049947 -Patch202: openssh-9.0p1-audit-log.patch - -# --- pam_ssh-agent --- -# make it build reusing the openssh sources -Patch300: pam_ssh_agent_auth-0.9.3-build.patch -# check return value of seteuid() -# https://sourceforge.net/p/pamsshagentauth/bugs/23/ -Patch301: pam_ssh_agent_auth-0.10.3-seteuid.patch -# explicitly make pam callbacks visible -Patch302: pam_ssh_agent_auth-0.9.2-visibility.patch -# update to current version of agent structure -Patch305: pam_ssh_agent_auth-0.9.3-agent_structure.patch -# remove prefixes to be able to build against current openssh library -Patch306: pam_ssh_agent_auth-0.10.2-compat.patch -# Fix NULL dereference from getpwuid() return value -# https://sourceforge.net/p/pamsshagentauth/bugs/22/ -Patch307: pam_ssh_agent_auth-0.10.2-dereference.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=2070113 -Patch308: pam_ssh_agent_auth-0.10.4-rsasha2.patch -Patch309: pam_ssh_agent-configure-c99.patch +Source22: parallel_test.sh +Source23: parallel_test.Makefile #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) -Patch400: openssh-7.8p1-role-mls.patch -#https://bugzilla.redhat.com/show_bug.cgi?id=781634 -Patch404: openssh-6.6p1-privsep-selinux.patch -#? -Patch502: openssh-6.6p1-keycat.patch - +Patch0001: 0001-openssh-7.8p1-role-mls.patch +Patch0002: 0002-openssh-6.6p1-keycat.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1644 -Patch601: openssh-6.6p1-allow-ip-opts.patch +Patch0003: 0003-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 -#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 +Patch0004: 0004-openssh-5.9p1-ipv6man.patch +Patch0005: 0005-openssh-5.8p2-sigpipe.patch +Patch0006: 0006-openssh-7.2p2-x11.patch +Patch0007: 0007-openssh-5.1p1-askpass-progress.patch #https://bugzilla.redhat.com/show_bug.cgi?id=198332 -Patch703: openssh-4.3p2-askpass-grab-info.patch +Patch0008: 0008-openssh-4.3p2-askpass-grab-info.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX) -Patch707: openssh-7.7p1-redhat.patch +Patch0009: 0009-openssh-8.7p1-redhat.patch # warn users for unsupported UsePAM=no (#757545) -Patch711: openssh-7.8p1-UsePAM-warning.patch - +Patch0010: 0010-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 +Patch0011: 0011-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 +Patch0012: 0012-openssh-6.6p1-force_krb.patch # Improve ccache handling in openssh (#991186, #1199363, #1566494) # https://bugzilla.mindrot.org/show_bug.cgi?id=2775 -Patch804: openssh-7.7p1-gssapi-new-unique.patch +Patch0013: 0013-openssh-7.7p1-gssapi-new-unique.patch # Respect k5login_directory option in krk5.conf (#1328243) -Patch805: openssh-7.2p2-k5login_directory.patch - - +Patch0014: 0014-openssh-7.2p2-k5login_directory.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1780 -Patch901: openssh-6.6p1-kuserok.patch +Patch0015: 0015-openssh-6.6p1-kuserok.patch # Use tty allocation for a remote scp (#985650) -Patch906: openssh-6.4p1-fromto-remote.patch -# privsep_preauth: use SELinux context from selinux-policy (#1008580) -Patch916: openssh-6.6.1p1-selinux-contexts.patch +Patch0016: 0016-openssh-6.4p1-fromto-remote.patch # log via monitor in chroots without /dev/log (#2681) -Patch918: openssh-6.6.1p1-log-in-chroot.patch +Patch0017: 0017-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 +Patch0018: 0018-openssh-6.6.1p1-scp-non-existing-directory.patch +# add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) +# CVE-2014-9278 +Patch0019: 0019-openssh-6.6p1-GSSAPIEnablek5users.patch # apply upstream patch and make sshd -T more consistent (#1187521) -Patch922: openssh-6.8p1-sshdT-output.patch +Patch0020: 0020-openssh-6.8p1-sshdT-output.patch # Add sftp option to force mode of created files (#1191055) -Patch926: openssh-6.7p1-sftp-force-permission.patch +Patch0021: 0021-openssh-6.7p1-sftp-force-permission.patch # make s390 use /dev/ crypto devices -- ignore closefrom -Patch939: openssh-7.2p2-s390-closefrom.patch -# Move MAX_DISPLAYS to a configuration option (#1341302) -Patch944: openssh-7.3p1-x11-max-displays.patch -# Help systemd to track the running service -Patch948: openssh-7.4p1-systemd.patch +Patch0022: 0022-openssh-7.2p2-s390-closefrom.patch # Pass inetd flags for SELinux down to openbsd compat level -Patch949: openssh-7.6p1-cleanup-selinux.patch +Patch0023: 0023-openssh-7.6p1-cleanup-selinux.patch # Sandbox adjustments for s390 and audit -Patch950: openssh-7.5p1-sandbox.patch -# PKCS#11 URIs (upstream #2817, 2nd iteration) -# https://github.com/Jakuje/openssh-portable/commits/jjelen-pkcs11 -# git show > ~/devel/fedora/openssh/openssh-8.0p1-pkcs11-uri.patch -Patch951: openssh-8.0p1-pkcs11-uri.patch +Patch0024: 0024-openssh-7.5p1-sandbox.patch # Unbreak scp between two IPv6 hosts (#1620333) -Patch953: openssh-7.8p1-scp-ipv6.patch +Patch0025: 0025-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 +Patch0026: 0026-openssh-8.0p1-crypto-policies.patch # Use OpenSSL KDF (#1631761) -Patch964: openssh-8.0p1-openssl-kdf.patch +Patch0027: 0027-openssh-8.0p1-openssl-kdf.patch # sk-dummy.so built with -fvisibility=hidden does not work -Patch965: openssh-8.2p1-visibility.patch +Patch0028: 0028-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 +Patch0029: 0029-openssh-8.2p1-x11-without-ipv6.patch # sshd provides PAM an incorrect error code (#1879503) -Patch975: openssh-8.0p1-preserve-pam-errors.patch - +Patch0030: 0030-openssh-8.0p1-preserve-pam-errors.patch # Implement kill switch for SCP protocol -Patch977: openssh-8.7p1-scp-kill-switch.patch - +Patch0031: 0031-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 +Patch0032: 0032-openssh-8.7p1-recursive-scp.patch +# Downstream alias for MinRSABits +Patch0033: 0033-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 - +Patch0034: 0034-openssh-8.7p1-ibmca.patch +#https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.redhat.com/show_bug.cgi?id=1171248 +# record pfs= field in CRYPTO_SESSION audit event +Patch0035: 0035-openssh-7.6p1-audit.patch +# Audit race condition in forked child (#1310684) +Patch0036: 0036-openssh-7.1p2-audit-race-condition.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2049947 +Patch0037: 0037-openssh-9.0p1-audit-log.patch +Patch0038: 0038-openssh-7.7p1-fips.patch # 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 - +Patch0039: 0039-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 - -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 +Patch0040: 0040-openssh-8.7p1-negotiate-supported-algs.patch +Patch0041: 0041-openssh-9.0p1-evp-fips-kex.patch +Patch0042: 0042-openssh-8.7p1-nohostsha1proof.patch +Patch0043: 0043-openssh-9.9p1-separate-keysign.patch +Patch0044: 0044-openssh-9.9p1-openssl-mlkem.patch +# https://www.openwall.com/lists/oss-security/2025/02/22/1 +Patch0045: 0045-openssh-9.9p2-error_processing.patch +# https://github.com/openssh/openssh-portable/pull/564 +Patch0046: 0046-Provide-better-error-for-non-supported-private-keys.patch +# https://github.com/openssh/openssh-portable/pull/567 +Patch0047: 0047-Ignore-bad-hostkeys-in-known_hosts-file.patch +# https://github.com/openssh/openssh-portable/pull/500 +Patch0048: 0048-support-authentication-indicators-in-GSSAPI.patch +Patch0049: 0049-NIST-curves-hybrid-KEX-implementation.patch +# landed upstream, to be removed after 10.3 +Patch0050: 0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch +# Move MAX_DISPLAYS to a configuration option (#1341302) +Patch0051: 0051-openssh-7.3p1-x11-max-displays.patch +# PKCS#11 URIs (upstream #2817, seriously reworked on rebasing to 10.2) +# https://github.com/Jakuje/openssh-portable/commits/jjelen-pkcs11 +Patch0052: 0052-openssh-10.2p1-pkcs11-uri.patch +#https://bugzilla.mindrot.org/show_bug.cgi?id=2581 +Patch1000: 1000-openssh-6.7p1-coverity.patch License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant Requires: /sbin/nologin +Requires: openssl-libs >= 3.5.0 %if ! %{no_gnome_askpass} BuildRequires: libX11-devel @@ -248,13 +193,14 @@ 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: perl-podlators BuildRequires: systemd-devel BuildRequires: systemd-rpm-macros BuildRequires: gcc make BuildRequires: p11-kit-devel BuildRequires: libfido2-devel +BuildRequires: libxcrypt-devel Recommends: p11-kit Obsoletes: openssh-ldap < 8.3p1-4 Obsoletes: openssh-cavs < 8.4p1-5 @@ -283,6 +229,10 @@ Summary: An open source SSH client applications Requires: openssh = %{version}-%{release} Requires: crypto-policies >= 20220824-1 +%package keysign +Summary: A helper program used for host-based authentication +Requires: openssh = %{version}-%{release} + %package server Summary: An open source SSH server daemon Requires: openssh = %{version}-%{release} @@ -303,12 +253,6 @@ Requires: openssh = %{version}-%{release} Summary: OpenSSH SK driver for test purposes Requires: openssh = %{version}-%{release} -%package -n pam_ssh_agent_auth -Summary: PAM module for authentication with ssh-agent -Version: %{pam_ssh_agent_ver} -Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}.1 -License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant AND OpenSSL - %description SSH (Secure SHell) is a program for logging into and executing commands on a remote machine. SSH is intended to replace rlogin and @@ -328,6 +272,11 @@ OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package includes the clients necessary to make encrypted connections to SSH servers. +%description keysign +OpenSSH is a free version of SSH (Secure SHell), a program for logging +into and executing commands on a remote machine. ssh-keysign is a +helper program used for host-based authentication disabled by default. + %description server OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains @@ -346,108 +295,14 @@ an X11 passphrase dialog for OpenSSH. %description sk-dummy This package contains a test SK driver used for OpenSSH test purposes -%description -n pam_ssh_agent_auth -This package contains a PAM module which can be used to authenticate -users using ssh keys stored in a ssh-agent. Through the use of the -forwarding of ssh-agent connection it also allows to authenticate with -remote ssh-agent instance. - -The module is most useful for su and sudo service stacks. - %prep gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} -%setup -q -a 4 - -%if %{pam_ssh_agent} -pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} -%patch -P 300 -p2 -b .psaa-build -%patch -P 301 -p2 -b .psaa-seteuid -%patch -P 302 -p2 -b .psaa-visibility -%patch -P 306 -p2 -b .psaa-compat -%patch -P 305 -p2 -b .psaa-agent -%patch -P 307 -p2 -b .psaa-deref -%patch -P 308 -p2 -b .rsasha2 -%patch -P 309 -p1 -b .psaa-configure-c99 -# Remove duplicate headers and library files -rm -f $(cat %{SOURCE5}) -popd -%endif - -%patch -P 400 -p1 -b .role-mls -%patch -P 404 -p1 -b .privsep-selinux - -%patch -P 502 -p1 -b .keycat - -%patch -P 601 -p1 -b .ip-opts -%patch -P 606 -p1 -b .ipv6man -%patch -P 607 -p1 -b .sigpipe -%patch -P 609 -p1 -b .x11 -%patch -P 702 -p1 -b .progress -%patch -P 703 -p1 -b .grab-info -%patch -P 707 -p1 -b .redhat -%patch -P 711 -p1 -b .log-usepam-no -# -%patch -P 800 -p1 -b .gsskex -%patch -P 801 -p1 -b .force_krb -%patch -P 804 -p1 -b .ccache_name -%patch -P 805 -p1 -b .k5login -# -%patch -P 901 -p1 -b .kuserok -%patch -P 906 -p1 -b .fromto-remote -%patch -P 916 -p1 -b .contexts -%patch -P 918 -p1 -b .log-in-chroot -%patch -P 919 -p1 -b .scp -%patch -P 802 -p1 -b .GSSAPIEnablek5users -%patch -P 922 -p1 -b .sshdt -%patch -P 926 -p1 -b .sftp-force-mode -%patch -P 939 -p1 -b .s390-dev -%patch -P 944 -p1 -b .x11max -%patch -P 948 -p1 -b .systemd -%patch -P 949 -p1 -b .refactor -%patch -P 950 -p1 -b .sandbox -%patch -P 951 -p1 -b .pkcs11-uri -%patch -P 953 -p1 -b .scp-ipv6 -%patch -P 962 -p1 -b .crypto-policies -%patch -P 963 -p1 -b .openssl-evp -%patch -P 964 -p1 -b .openssl-kdf -%patch -P 965 -p1 -b .visibility -%patch -P 966 -p1 -b .x11-ipv6 -%patch -P 974 -p1 -b .keygen-strip-doseol -%patch -P 975 -p1 -b .preserve-pam-errors - -%patch -P 977 -p1 -b .kill-scp - -%patch -P 981 -p1 -b .scp-sftpdirs -%patch -P 982 -p1 -b .minrsabits -%patch -P 984 -p1 -b .ibmca - -%patch -P 200 -p1 -b .audit -%patch -P 201 -p1 -b .audit-race -%patch -P 202 -p1 -b .audit-log -%patch -P 700 -p1 -b .fips - -%patch -P 1002 -p1 -b .ssh-manpage - -%patch -P 1006 -p1 -b .negotiate-supported-algs - -%patch -P 1012 -p1 -b .evp-fips-dh -%patch -P 1013 -p1 -b .evp-fips-ecdh -%patch -P 1014 -p1 -b .nosha1hostproof -%patch -P 1015 -p1 -b .cve-2023-38408 -%patch -P 1016 -p1 -b .ossl-version - -%patch -P 100 -p1 -b .coverity +%autosetup -T -b 0 -p1 autoreconf -pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} -autoreconf -popd %build %set_build_flags -# the -fvisibility=hidden is needed for clean build of the pam_ssh_agent_auth -# it is needed for lib(open)ssh build too since it is linked to the pam module too -CFLAGS="$CFLAGS -fvisibility=hidden"; export CFLAGS %if %{pie} %ifarch s390 s390x sparc sparcv9 sparc64 CFLAGS="$CFLAGS -fPIC" @@ -481,16 +336,14 @@ fi --sysconfdir=%{_sysconfdir}/ssh \ --libexecdir=%{_libexecdir}/openssh \ --datadir=%{_datadir}/openssh \ - --with-default-path=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin \ - --with-superuser-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \ + --with-default-path=/usr/local/bin:/usr/bin \ + --with-superuser-path=/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` \ - --with-systemd \ --with-default-pkcs11-provider=yes \ --with-security-key-builtin=yes \ --with-pam \ @@ -538,22 +391,9 @@ fi popd %endif -%if %{pam_ssh_agent} -pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} -LDFLAGS="$SAVE_LDFLAGS" -%configure --with-selinux \ - --libexecdir=/%{_libdir}/security \ - --with-mantype=man \ - --without-openssl-header-check `# The check is broken` -%make_build -popd -%endif - %check -#to run tests use "--with check" -%if %{?_with_check:1}%{!?_with_check:0} -make tests -%endif +OPENSSL_CONF=/dev/null %{SOURCE22} %{SOURCE23} # ./parallel_tests.sh parallel_tests.Makefile +#make tests %install rm -rf $RPM_BUILD_ROOT @@ -611,12 +451,6 @@ rm -f $RPM_BUILD_ROOT/etc/profile.d/gnome-ssh-askpass.* perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/* -%if %{pam_ssh_agent} -pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} -%make_install -popd -%endif - install -m 755 -d $RPM_BUILD_ROOT%{_libdir}/sshtest/ install -m 755 regress/misc/sk-dummy/sk-dummy.so $RPM_BUILD_ROOT%{_libdir}/sshtest @@ -667,8 +501,6 @@ test -f %{sysconfig_anaconda} && \ %attr(0755,root,root) %{_bindir}/ssh-keygen %attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1* %attr(0755,root,root) %dir %{_libexecdir}/openssh -%attr(4555,root,root) %{_libexecdir}/openssh/ssh-keysign -%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* %files clients %attr(0755,root,root) %{_bindir}/ssh @@ -696,9 +528,15 @@ test -f %{sysconfig_anaconda} && \ %attr(0644,root,root) %{_userunitdir}/ssh-agent.service %attr(0644,root,root) %{_userunitdir}/ssh-agent.socket +%files keysign +%attr(4555,root,root) %{_libexecdir}/openssh/ssh-keysign +%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* + %files server %dir %attr(0711,root,root) %{_datadir}/empty.sshd %attr(0755,root,root) %{_sbindir}/sshd +%attr(0755,root,root) %{_libexecdir}/openssh/sshd-session +%attr(0755,root,root) %{_libexecdir}/openssh/sshd-auth %attr(0755,root,root) %{_libexecdir}/openssh/sftp-server %attr(0755,root,root) %{_libexecdir}/openssh/sshd-keygen %attr(0644,root,root) %{_mandir}/man5/sshd_config.5* @@ -730,20 +568,184 @@ test -f %{sysconfig_anaconda} && \ %files askpass %attr(0644,root,root) %{_sysconfdir}/profile.d/gnome-ssh-askpass.* %attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass -%attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass +%{_libexecdir}/openssh/ssh-askpass %endif %files sk-dummy %attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so -%if %{pam_ssh_agent} -%files -n pam_ssh_agent_auth -%license pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}/OPENSSH_LICENSE -%attr(0755,root,root) %{_libdir}/security/pam_ssh_agent_auth.so -%attr(0644,root,root) %{_mandir}/man8/pam_ssh_agent_auth.8* -%endif - %changelog +* Wed Dec 17 2025 Dmitry Belyavskiy - 10.2p1-1 +- Rebase to OpenSSH 10.2p1 + +* Wed Dec 10 2025 Pavol Žáčik - 10.0p1-10 +- Update gssapi-keyex patch to not abort KEX without hostkey + +* Mon Dec 01 2025 Dmitry Belyavskiy - 10.0p1-9 +- rebuilt + +* Mon Nov 03 2025 Dmitry Belyavskiy - 10.0p1-8 +- Implement mlkem768nistp256-sha256 and mlkem1024nistp384-sha384 KEX methods + +* Mon Sep 15 2025 Dmitry Belyavskiy - 10.0p1-7 +- rebuilt + +* Thu Aug 28 2025 Dmitry Belyavskiy - 10.0p1-6 +- Enable GSS KEX in FIPS mode + +* Thu Jul 24 2025 Fedora Release Engineering - 10.0p1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Fri Jun 27 2025 Dmitry Belyavskiy - 10.0p1-4 +- Update sshd@.service to follow upstream, mostly support ephemeral sshd keys + Submitted by Allison Karlitskaya (https://src.fedoraproject.org/rpms/openssh/pull-request/101) + Needs a SELinux counterpart. + Related: rhbz#2374928 + +* Mon Jun 09 2025 Dmitry Belyavskiy - 10.0p1-3 +- Apply patches forgot in previous respin + +* Mon May 19 2025 Dmitry Belyavskiy - 10.0p1-2 +- Provide better diagnostics for non-supported private keys + (https://github.com/openssh/openssh-portable/pull/564) +- Ignore too short hostkeys in known_hosts file + (https://github.com/openssh/openssh-portable/pull/567) +- Switch to systemd-socket activation for ssh-agent + Resolves: rhbz#2181353 + +* Fri May 16 2025 Dmitry Belyavskiy - 10.0p1-1 +- Rebase to OpenSSH 10.0p1 + +* Thu Apr 17 2025 Dmitry Belyavskiy - 9.9p1-15 +- Require OpenSSL 3.5 to support PQ crypto +- Suppress systemd warning on restart sshd + +* Tue Mar 18 2025 Zbigniew Jędrzejewski-Szmek - 9.9p1-14 +- Remove /usr/local/sbin from the default path too + +* Tue Mar 18 2025 Dmitry Belyavskiy - 9.9p1-13 +- Remove /usr/sbin from the default path + Resolves: rhbz#2352387 +- Export and accept COLORTERM + Resolves: rhbz#2352653 + +* Thu Mar 06 2025 Dmitry Belyavskiy - 9.9p1-12 +- Update ssh-keysign permission for RPM linter + +* Wed Mar 05 2025 Dmitry Belyavskiy - 9.9p1-11 +- Use OpenSSL ML-KEM implementation instead of the native one + +* Tue Feb 25 2025 Dmitry Belyavskiy - 9.9p1-10 +- Some minor fixes from Rocky Linux + https://www.openwall.com/lists/oss-security/2025/02/22/1 + +* Tue Feb 18 2025 Dmitry Belyavskiy - 9.9p1-9 +- Fix regression of Match directive processing +- Fix missing error codes set and invalid error code checks in OpenSSH. It + prevents memory exhaustion attack and a MITM attack when VerifyHostKeyDNS + is on (CVE-2025-26465, CVE-2025-26466). + +* Sat Feb 01 2025 Björn Esser - 9.9p1-8.1 +- Add explicit BR: libxcrypt-devel + +* Wed Jan 29 2025 FeRD (Frank Dana) - 9.9p1-8 +- Replace deprecated (since 8.7) ChallengeResponseAuthentication + with KbdInteractiveAuthentication, in redhat sshd config + +* Mon Jan 27 2025 Dmitry Belyavskiy - 9.9p1-7 +- Fix regression of Match directive processing + Resolves: rhbz#2341769 + +* Mon Jan 27 2025 Dmitry Belyavskiy - 9.9p1-6 +- Remove pam-ssh-agent subcomponent + Resolves: rhbz#2338440 + +* Fri Jan 17 2025 Fedora Release Engineering - 9.9p1-5.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Mon Oct 28 2024 Dmitry Belyavskiy - 9.9p1-5 +- Fix MLKEM for BE platforms + +* Wed Oct 16 2024 Dmitry Belyavskiy - 9.9p1-4 +- Resolve memory management issues after rebase +- Define OPTIONS env in systemd modules (https://src.fedoraproject.org/rpms/openssh/pull-request/92) + +* Fri Oct 11 2024 Dmitry Belyavskiy - 9.9p1-3 +- Separate ssh-keysign to a dedicated package +- Use FIPS KEX defaults in FIPS mode + +* Thu Oct 10 2024 Dmitry Belyavskiy - 9.9p1-2 +- Update version of pam_ssh_agent_auth + +* Tue Oct 08 2024 Dmitry Belyavskiy - 9.9p1-1 +- Update to OpenSSH 9.9p1 + +* Tue Sep 03 2024 Dmitry Belyavskiy - 9.8p1-4 +- Synchronize patches from Red Hat + +* Mon Aug 05 2024 Dmitry Belyavskiy - 9.8p1-3 +- Sshd now proposes to enter password again when a non-existing user is specified + +* Fri Jul 26 2024 Dmitry Belyavskiy - 9.8p1-2 +- Change default key type in FIPS mode + +* Mon Jul 22 2024 Dmitry Belyavskiy - 9.8p1-1 +- Update to OpenSSH 9.8p1 + +* Thu Jul 18 2024 Fedora Release Engineering - 9.6p1-1.14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Tue Jul 02 2024 Dmitry Belyavskiy - 9.6p1-1.13 +- rebuilt + +* Mon Jul 01 2024 Gordon Messmer - 9.6p1-12 +- Patch 9.6p1 for CVE-2024-6387 + +* Mon Jul 01 2024 Gordon Messmer - 9.6p1-11 +- Shorten paths used for parallel tests to fix BZ#2295117 + +* Thu May 09 2024 Zoltan Fridrich - 9.6p1-10 +- Correctly audit hostname and IP address +- Make default key sizes configurable in sshd-keygen + +* Wed Apr 24 2024 Dmitry Belyavskiy - 9.6p1-1.9 +- Use OpenSSL SSH KDF implementation - s390x fixup + +* Wed Apr 24 2024 Dmitry Belyavskiy - 9.6p1-1.8 +- Use OpenSSL SSH KDF implementation + +* Wed Apr 17 2024 Dmitry Belyavskiy - 9.6p1-1.7 +- Only set PAM_RHOST if the remote host is not "UNKNOWN" + https://src.fedoraproject.org/rpms/openssh/pull-request/71 + Patch by Daan De Meyer +- Some spec cleanup + https://src.fedoraproject.org/rpms/openssh/pull-request/74 + by Zbigniew Jędrzejewski-Szmek + +* Thu Apr 04 2024 Dmitry Belyavskiy - 9.6p1-1.6 +- rebuilt + +* Thu Apr 04 2024 Dmitry Belyavskiy - 9.6p1-1.5 +- rebuilt + +* Tue Apr 02 2024 Gordon Messmer - 9.6p1-1.4 +- Build OpenSSH without libsystemd dependency, using reference implementation + +* Wed Mar 13 2024 Dmitry Belyavskiy - 9.6p1-1.3 +- Build OpenSSH without engine support +- Make tests run at build phase (using parallel run mechanism by Alexander Sosedkin) + +* Thu Jan 25 2024 Fedora Release Engineering - 9.6p1-1.2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sun Jan 21 2024 Fedora Release Engineering - 9.6p1-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Tue Dec 26 2023 Daniel Milnes - 9.6p1-1 +- Update to OpenSSH 9.6 + Original patches from https://src.fedoraproject.org/rpms/openssh/pull-request/63 + Tuned by Dmitry Belyavskiy for GSS and PKCS#11 URI processing + * Fri Dec 22 2023 Florian Weimer - 9.3p1-13.1 - Fix type errors in downstream gssapi-keyex patch diff --git a/pam_ssh_agent-configure-c99.patch b/pam_ssh_agent-configure-c99.patch deleted file mode 100644 index bc40434..0000000 --- a/pam_ssh_agent-configure-c99.patch +++ /dev/null @@ -1,249 +0,0 @@ -configure.ac: Improve C99 compatibility - -Future compilers will not support implicit declarations and implicit -ints by default. This means that configure probes which rely on them -will fail unconditionally, without actually testing anything. - -The changes mostly mirror what has been implemented in the openssh -repository, but had to be adapted somewhat because of drift between -the two versions of configure.ac. - -Sam James has submitted similar fixes upstream: - - - -diff --git a/configure.ac b/configure.ac -index 6496679..d927b62 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -500,10 +500,10 @@ int main(void) { exit(0); } - AC_DEFINE(HAVE_BUNDLE, 1, [Define if your system uses bundles instead of ELF shared objects]) - AC_MSG_CHECKING(if we have working getaddrinfo) - AC_TRY_RUN([#include --main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) -- exit(0); -+int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) -+ return 0; - else -- exit(1); -+ return 1; - }], [AC_MSG_RESULT(working)], - [AC_MSG_RESULT(buggy) - AC_DEFINE(BROKEN_GETADDRINFO, 1, [getaddrinfo is broken (if present)])], -@@ -917,8 +917,8 @@ AC_SUBST(LDFLAGS_SHARED) - AC_MSG_CHECKING(compiler and flags for sanity) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([ --#include --int main(){exit(0);} -+#include -+int main(void){exit(0);} - ])], - [ AC_MSG_RESULT(yes) ], - [ -@@ -951,9 +951,9 @@ int main(int argc, char **argv) { - strncpy(buf,"/etc", 32); - s = dirname(buf); - if (!s || strncmp(s, "/", 32) != 0) { -- exit(1); -+ return 1; - } else { -- exit(0); -+ return 0; - } - } - ]])], -@@ -1102,7 +1102,7 @@ AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include - #include --int main(void){struct dirent d;exit(sizeof(d.d_name)<=sizeof(char));} -+int main(void){struct dirent d;return sizeof(d.d_name)<=sizeof(char);} - ]])], - [AC_MSG_RESULT(yes)], - [ -@@ -1327,8 +1327,10 @@ AC_CHECK_FUNCS(setresuid, [ - AC_MSG_CHECKING(if setresuid seems to work) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -+#define _GNU_SOURCE - #include - #include -+#include - int main(){errno=0; setresuid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);} - ]])], - [AC_MSG_RESULT(yes)], -@@ -1344,8 +1346,10 @@ AC_CHECK_FUNCS(setresgid, [ - AC_MSG_CHECKING(if setresgid seems to work) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -+#define _GNU_SOURCE - #include - #include -+#include - int main(){errno=0; setresgid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);} - ]])], - [AC_MSG_RESULT(yes)], -@@ -1384,7 +1388,7 @@ if test "x$ac_cv_func_snprintf" = "xyes" ; then - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include --int main(void){char b[5];snprintf(b,5,"123456789");exit(b[4]!='\0');} -+int main(void){char b[5];snprintf(b,5,"123456789");return b[4]!='\0';} - ]])], - [AC_MSG_RESULT(yes)], - [ -@@ -1418,7 +1422,7 @@ int x_snprintf(char *str,size_t count,const char *fmt,...) - int main(void) - { - char x[1]; -- exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); -+ return x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1; - } ]])], - [AC_MSG_RESULT(yes)], - [ -@@ -1467,7 +1471,8 @@ AC_MSG_CHECKING([for (overly) strict mkstemp]) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include --main() { char template[]="conftest.mkstemp-test"; -+#include -+int main(void) { char template[]="conftest.mkstemp-test"; - if (mkstemp(template) == -1) - exit(1); - unlink(template); exit(0); -@@ -1492,10 +1497,14 @@ if test ! -z "$check_for_openpty_ctty_bug"; then - AC_MSG_CHECKING(if openpty correctly handles controlling tty) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -+#include - #include - #include - #include - #include -+#ifdef HAVE_PTY_H -+#include -+#endif - - int - main() -@@ -1543,6 +1552,7 @@ if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include -+#include - #include - #include - #include -@@ -1748,6 +1758,7 @@ AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL, 1, - AC_MSG_CHECKING([OpenSSL header version]) - AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ -+#include - #include - #include - #include -@@ -1794,12 +1805,12 @@ int main(void) { - - fd = fopen(DATA,"w"); - if(fd == NULL) -- exit(1); -+ return 1; - - if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) -- exit(1); -+ return 1; - -- exit(0); -+ return 0; - } - ]])], - [ -@@ -1829,7 +1840,7 @@ AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include - #include --int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); } -+int main(void) { return SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1; } - ]])], - [ - AC_MSG_RESULT(yes) -@@ -2598,7 +2609,7 @@ dnl test snprintf (broken on SCO w/gcc) - #include - #include - #ifdef HAVE_SNPRINTF --main() -+int main(void) - { - char buf[50]; - char expected_out[50]; -@@ -2611,11 +2622,11 @@ main() - strcpy(expected_out, "9223372036854775807"); - snprintf(buf, mazsize, "%lld", num); - if(strcmp(buf, expected_out) != 0) -- exit(1); -- exit(0); -+ return 1; -+ return 0; - } - #else --main() { exit(0); } -+int main(void) { return 0; } - #endif - ]])], [ true ], [ AC_DEFINE(BROKEN_SNPRINTF) ], - AC_MSG_WARN([cross compiling: Assuming working snprintf()]) -@@ -2746,11 +2757,11 @@ AC_CACHE_CHECK([for msg_accrights field in struct msghdr], - int main() { - #ifdef msg_accrights - #error "msg_accrights is a macro" --exit(1); -+return 1; - #endif - struct msghdr m; - m.msg_accrights = 0; --exit(0); -+return 0; - } - ])], - [ ac_cv_have_accrights_in_msghdr="yes" ], -@@ -2773,11 +2784,11 @@ AC_CACHE_CHECK([for msg_control field in struct msghdr], - int main() { - #ifdef msg_control - #error "msg_control is a macro" --exit(1); -+return 1; - #endif - struct msghdr m; - m.msg_control = 0; --exit(0); -+return 0; - } - ])], - [ ac_cv_have_control_in_msghdr="yes" ], -@@ -2791,7 +2802,7 @@ if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then - fi - - AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ -- AC_TRY_LINK([], -+ AC_TRY_LINK([#include ], - [ extern char *__progname; printf("%s", __progname); ], - [ ac_cv_libc_defines___progname="yes" ], - [ ac_cv_libc_defines___progname="no" ] -@@ -2871,7 +2882,7 @@ if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then - fi - - AC_CACHE_CHECK([if libc defines sys_errlist], ac_cv_libc_defines_sys_errlist, [ -- AC_TRY_LINK([], -+ AC_TRY_LINK([#include ], - [ extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);], - [ ac_cv_libc_defines_sys_errlist="yes" ], - [ ac_cv_libc_defines_sys_errlist="no" ] -@@ -2884,7 +2895,7 @@ fi - - - AC_CACHE_CHECK([if libc defines sys_nerr], ac_cv_libc_defines_sys_nerr, [ -- AC_TRY_LINK([], -+ AC_TRY_LINK([#include ], - [ extern int sys_nerr; printf("%i", sys_nerr);], - [ ac_cv_libc_defines_sys_nerr="yes" ], - [ ac_cv_libc_defines_sys_nerr="no" ] diff --git a/pam_ssh_agent-rmheaders b/pam_ssh_agent-rmheaders deleted file mode 100644 index ab5899f..0000000 --- a/pam_ssh_agent-rmheaders +++ /dev/null @@ -1,36 +0,0 @@ -authfd.c -authfd.h -atomicio.c -atomicio.h -bufaux.c -bufbn.c -buffer.h -buffer.c -cleanup.c -cipher.h -compat.h -entropy.c -entropy.h -fatal.c -includes.h -kex.h -key.c -key.h -log.c -log.h -match.h -misc.c -misc.h -pathnames.h -platform.h -rsa.h -ssh-dss.c -ssh-rsa.c -ssh.h -ssh2.h -uidswap.c -uidswap.h -uuencode.c -uuencode.h -xmalloc.c -xmalloc.h diff --git a/pam_ssh_agent_auth-0.10.2-compat.patch b/pam_ssh_agent_auth-0.10.2-compat.patch deleted file mode 100644 index 0822b61..0000000 --- a/pam_ssh_agent_auth-0.10.2-compat.patch +++ /dev/null @@ -1,992 +0,0 @@ -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c 2020-09-23 10:52:16.424001475 +0200 -@@ -27,6 +27,7 @@ - * or implied, of Jamie Beverly. - */ - -+#include - #include - #include - #include -@@ -66,8 +67,8 @@ proc_pid_cmdline(char *** inargv) - case EOF: - case '\0': - if (len > 0) { -- argv = pamsshagentauth_xrealloc(argv, count + 1, sizeof(*argv)); -- argv[count] = pamsshagentauth_xcalloc(len + 1, sizeof(*argv[count])); -+ argv = xreallocarray(argv, count + 1, sizeof(*argv)); -+ argv[count] = xcalloc(len + 1, sizeof(*argv[count])); - strncpy(argv[count++], argbuf, len); - memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); - len = 0; -@@ -106,9 +107,9 @@ pamsshagentauth_free_command_line(char * - { - size_t i; - for (i = 0; i < n_args; i++) -- pamsshagentauth_xfree(argv[i]); -+ free(argv[i]); - -- pamsshagentauth_xfree(argv); -+ free(argv); - return; - } - -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h 2020-09-23 10:52:16.424001475 +0200 -@@ -30,8 +30,8 @@ - #include "openbsd-compat/sys-queue.h" - #include "xmalloc.h" - #include "log.h" --#include "buffer.h" --#include "key.h" -+#include "sshbuf.h" -+#include "sshkey.h" - #include "authfd.h" - #include - -@@ -41,7 +41,7 @@ typedef struct idlist Idlist; - struct identity { - TAILQ_ENTRY(identity) next; - AuthenticationConnection *ac; /* set if agent supports key */ -- Key *key; /* public/private key */ -+ struct sshkey *key; /* public/private key */ - char *filename; /* comment for agent-only keys */ - int tried; - int isprivate; /* key points to the private key */ -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat 2020-09-23 10:52:16.421001434 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c 2020-09-23 10:52:16.424001475 +0200 -@@ -36,8 +36,8 @@ - #include "openbsd-compat/sys-queue.h" - #include "xmalloc.h" - #include "log.h" --#include "buffer.h" --#include "key.h" -+#include "sshbuf.h" -+#include "sshkey.h" - #include "authfd.h" - #include - #include -@@ -58,6 +58,8 @@ - #include "get_command_line.h" - extern char **environ; - -+#define PAM_SSH_AGENT_AUTH_REQUESTv1 101 -+ - /* - * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user - * A cursory check is done, but to avoid race conditions, it is necessary -@@ -77,7 +79,7 @@ log_action(char ** action, size_t count) - if (count == 0) - return NULL; - -- buf = pamsshagentauth_xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); -+ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); - for (i = 0; i < count; i++) { - strcat(buf, (i > 0) ? " '" : "'"); - strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); -@@ -87,21 +89,25 @@ log_action(char ** action, size_t count) - } - - void --agent_action(Buffer *buf, char ** action, size_t count) -+agent_action(struct sshbuf **buf, char ** action, size_t count) - { - size_t i; -- pamsshagentauth_buffer_init(buf); -+ int r; - -- pamsshagentauth_buffer_put_int(buf, count); -+ if ((*buf = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(*buf, count)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - - for (i = 0; i < count; i++) { -- pamsshagentauth_buffer_put_cstring(buf, action[i]); -+ if ((r = sshbuf_put_cstring(*buf, action[i])) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - } - } - - --void --pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, -+static void -+pamsshagentauth_session_id2_gen(struct sshbuf ** session_id2, const char * user, - const char * ruser, const char * servicename) - { - u_char *cookie = NULL; -@@ -114,22 +120,23 @@ pamsshagentauth_session_id2_gen(Buffer * - char ** reported_argv = NULL; - size_t count = 0; - char * action_logbuf = NULL; -- Buffer action_agentbuf; -+ struct sshbuf *action_agentbuf = NULL; - uint8_t free_logbuf = 0; - char * retc; - int32_t reti; -+ int r; - -- rnd = pamsshagentauth_arc4random(); -+ rnd = arc4random(); - cookie_len = ((uint8_t) rnd); - while (cookie_len < 16) { - cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */ - } - -- cookie = pamsshagentauth_xcalloc(1,cookie_len); -+ cookie = xcalloc(1, cookie_len); - - for (i = 0; i < cookie_len; i++) { - if (i % 4 == 0) { -- rnd = pamsshagentauth_arc4random(); -+ rnd = arc4random(); - } - cookie[i] = (u_char) rnd; - rnd >>= 8; -@@ -144,7 +151,8 @@ pamsshagentauth_session_id2_gen(Buffer * - } - else { - action_logbuf = "unknown on this platform"; -- pamsshagentauth_buffer_init(&action_agentbuf); /* stays empty, means unavailable */ -+ if ((action_agentbuf = sshbuf_new()) == NULL) /* stays empty, means unavailable */ -+ fatal("%s: sshbuf_new failed", __func__); - } - - /* -@@ -161,35 +169,39 @@ pamsshagentauth_session_id2_gen(Buffer * - retc = getcwd(pwd, sizeof(pwd) - 1); - time(&ts); - -- pamsshagentauth_buffer_init(session_id2); -+ if ((*session_id2 = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); - -- pamsshagentauth_buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); -- /* pamsshagentauth_debug3("cookie: %s", pamsshagentauth_tohex(cookie, cookie_len)); */ -- pamsshagentauth_buffer_put_string(session_id2, cookie, cookie_len); -- /* pamsshagentauth_debug3("user: %s", user); */ -- pamsshagentauth_buffer_put_cstring(session_id2, user); -- /* pamsshagentauth_debug3("ruser: %s", ruser); */ -- pamsshagentauth_buffer_put_cstring(session_id2, ruser); -- /* pamsshagentauth_debug3("servicename: %s", servicename); */ -- pamsshagentauth_buffer_put_cstring(session_id2, servicename); -- /* pamsshagentauth_debug3("pwd: %s", pwd); */ -- if(retc) -- pamsshagentauth_buffer_put_cstring(session_id2, pwd); -- else -- pamsshagentauth_buffer_put_cstring(session_id2, ""); -- /* pamsshagentauth_debug3("action: %s", action_logbuf); */ -- pamsshagentauth_buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); -+ if ((r = sshbuf_put_u32(*session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1)) != 0 || -+ (r = sshbuf_put_string(*session_id2, cookie, cookie_len)) != 0 || -+ (r = sshbuf_put_cstring(*session_id2, user)) != 0 || -+ (r = sshbuf_put_cstring(*session_id2, ruser)) != 0 || -+ (r = sshbuf_put_cstring(*session_id2, servicename)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ if (retc) { -+ if ((r = sshbuf_put_cstring(*session_id2, pwd)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ } else { -+ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ } -+ if ((r = sshbuf_put_stringb(*session_id2, action_agentbuf)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - if (free_logbuf) { -- pamsshagentauth_xfree(action_logbuf); -- pamsshagentauth_buffer_free(&action_agentbuf); -+ free(action_logbuf); -+ sshbuf_free(action_agentbuf); -+ } -+ /* debug3("hostname: %s", hostname); */ -+ if (reti >= 0) { -+ if ((r = sshbuf_put_cstring(*session_id2, hostname)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ } else { -+ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - } -- /* pamsshagentauth_debug3("hostname: %s", hostname); */ -- if(reti >= 0) -- pamsshagentauth_buffer_put_cstring(session_id2, hostname); -- else -- pamsshagentauth_buffer_put_cstring(session_id2, ""); -- /* pamsshagentauth_debug3("ts: %ld", ts); */ -- pamsshagentauth_buffer_put_int64(session_id2, (uint64_t) ts); -+ /* debug3("ts: %ld", ts); */ -+ if ((r = sshbuf_put_u64(*session_id2, (uint64_t) ts)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - - free(cookie); - return; -@@ -278,7 +290,8 @@ ssh_get_authentication_connection_for_ui - - auth = xmalloc(sizeof(*auth)); - auth->fd = sock; -- buffer_init(&auth->identities); -+ if ((auth->identities = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); - auth->howmany = 0; - - return auth; -@@ -287,9 +300,9 @@ ssh_get_authentication_connection_for_ui - int - pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) - { -- Buffer session_id2 = { 0 }; -+ struct sshbuf *session_id2 = NULL; - Identity *id; -- Key *key; -+ struct sshkey *key; - AuthenticationConnection *ac; - char *comment; - uint8_t retval = 0; -@@ -299,31 +312,30 @@ pamsshagentauth_find_authorized_keys(con - pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); - - if ((ac = ssh_get_authentication_connection_for_uid(uid))) { -- pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); -+ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); - for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) - { - if(key != NULL) { -- id = pamsshagentauth_xcalloc(1, sizeof(*id)); -+ id = xcalloc(1, sizeof(*id)); - id->key = key; - id->filename = comment; - id->ac = ac; -- if(userauth_pubkey_from_id(ruser, id, &session_id2)) { -+ if(userauth_pubkey_from_id(ruser, id, session_id2)) { - retval = 1; - } -- pamsshagentauth_xfree(id->filename); -- pamsshagentauth_key_free(id->key); -- pamsshagentauth_xfree(id); -+ free(id->filename); -+ key_free(id->key); -+ free(id); - if(retval == 1) - break; - } - } -- pamsshagentauth_buffer_free(&session_id2); -+ sshbuf_free(session_id2); - ssh_close_authentication_connection(ac); - } - else { -- pamsshagentauth_verbose("No ssh-agent could be contacted"); -+ verbose("No ssh-agent could be contacted"); - } -- /* pamsshagentauth_xfree(session_id2); */ - EVP_cleanup(); - return retval; - } -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat 2020-09-23 10:52:16.423001461 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c 2020-09-23 10:53:10.631727657 +0200 -@@ -106,7 +106,7 @@ pam_sm_authenticate(pam_handle_t * pamh, - * a patch 8-) - */ - #if ! HAVE___PROGNAME || HAVE_BUNDLE -- __progname = pamsshagentauth_xstrdup(servicename); -+ __progname = xstrdup(servicename); - #endif - - for(i = argc, argv_ptr = (char **) argv; i > 0; ++argv_ptr, i--) { -@@ -132,11 +132,11 @@ pam_sm_authenticate(pam_handle_t * pamh, - #endif - } - -- pamsshagentauth_log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); -+ log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); - pam_get_item(pamh, PAM_USER, (void *) &user); - pam_get_item(pamh, PAM_RUSER, (void *) &ruser_ptr); - -- pamsshagentauth_verbose("Beginning pam_ssh_agent_auth for user %s", user); -+ verbose("Beginning pam_ssh_agent_auth for user %s", user); - - if(ruser_ptr) { - strncpy(ruser, ruser_ptr, sizeof(ruser) - 1); -@@ -151,12 +151,12 @@ pam_sm_authenticate(pam_handle_t * pamh, - #ifdef ENABLE_SUDO_HACK - if( (strlen(sudo_service_name) > 0) && strncasecmp(servicename, sudo_service_name, sizeof(sudo_service_name) - 1) == 0 && getenv("SUDO_USER") ) { - strncpy(ruser, getenv("SUDO_USER"), sizeof(ruser) - 1 ); -- pamsshagentauth_verbose( "Using environment variable SUDO_USER (%s)", ruser ); -+ verbose( "Using environment variable SUDO_USER (%s)", ruser ); - } else - #endif - { - if( ! getpwuid(getuid()) ) { -- pamsshagentauth_verbose("Unable to getpwuid(getuid())"); -+ verbose("Unable to getpwuid(getuid())"); - goto cleanexit; - } - strncpy(ruser, getpwuid(getuid())->pw_name, sizeof(ruser) - 1); -@@ -165,11 +165,11 @@ pam_sm_authenticate(pam_handle_t * pamh, - - /* Might as well explicitely confirm the user exists here */ - if(! getpwnam(ruser) ) { -- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", ruser); -+ verbose("getpwnam(%s) failed, bailing out", ruser); - goto cleanexit; - } - if( ! getpwnam(user) ) { -- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", user); -+ verbose("getpwnam(%s) failed, bailing out", user); - goto cleanexit; - } - -@@ -179,8 +179,8 @@ pam_sm_authenticate(pam_handle_t * pamh, - */ - parse_authorized_key_file(user, authorized_keys_file_input); - } else { -- pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys"); -- authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys"); -+ verbose("Using default file=/etc/security/authorized_keys"); -+ authorized_keys_file = xstrdup("/etc/security/authorized_keys"); - } - - /* -@@ -189,7 +189,7 @@ pam_sm_authenticate(pam_handle_t * pamh, - */ - - if(user && strlen(ruser) > 0) { -- pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); -+ verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); - - /* - * Attempt to read data from the sshd if we're being called as an auth agent. -@@ -197,10 +197,10 @@ pam_sm_authenticate(pam_handle_t * pamh, - const char* ssh_user_auth = pam_getenv(pamh, "SSH_AUTH_INFO_0"); - int sshd_service = strncasecmp(servicename, sshd_service_name, sizeof(sshd_service_name) - 1); - if (sshd_service == 0 && ssh_user_auth != NULL) { -- pamsshagentauth_verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); -+ verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); - if (userauth_pubkey_from_pam(ruser, ssh_user_auth) > 0) { - retval = PAM_SUCCESS; -- pamsshagentauth_logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); -+ logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); - goto cleanexit; - } - } -@@ -208,13 +208,13 @@ pam_sm_authenticate(pam_handle_t * pamh, - * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user - */ - if(pamsshagentauth_find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */ -- pamsshagentauth_logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); -+ logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); - retval = PAM_SUCCESS; - } else { -- pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); -+ logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); - } - } else { -- pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); -+ logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); - } - - cleanexit: -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c 2020-09-23 10:52:16.424001475 +0200 -@@ -66,8 +66,8 @@ - #include "xmalloc.h" - #include "match.h" - #include "log.h" --#include "buffer.h" --#include "key.h" -+#include "sshbuf.h" -+#include "sshkey.h" - #include "misc.h" - - #include "xmalloc.h" -@@ -77,7 +77,6 @@ - #include "pathnames.h" - #include "secure_filename.h" - --#include "identity.h" - #include "pam_user_key_allowed2.h" - - extern char *authorized_keys_file; -@@ -117,12 +116,12 @@ parse_authorized_key_file(const char *us - } else { - slash_ptr = strchr(auth_keys_file_buf, '/'); - if(!slash_ptr) -- pamsshagentauth_fatal -+ fatal - ("cannot expand tilde in path without a `/'"); - - owner_uname_len = slash_ptr - auth_keys_file_buf - 1; - if(owner_uname_len > (sizeof(owner_uname) - 1)) -- pamsshagentauth_fatal("Username too long"); -+ fatal("Username too long"); - - strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); - if(!authorized_keys_file_allowed_owner_uid) -@@ -130,11 +129,11 @@ parse_authorized_key_file(const char *us - getpwnam(owner_uname)->pw_uid; - } - authorized_keys_file = -- pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, -+ tilde_expand_filename(auth_keys_file_buf, - authorized_keys_file_allowed_owner_uid); - strncpy(auth_keys_file_buf, authorized_keys_file, - sizeof(auth_keys_file_buf) - 1); -- pamsshagentauth_xfree(authorized_keys_file) /* when we -+ free(authorized_keys_file) /* when we - percent_expand - later, we'd step - on this, so free -@@ -150,13 +149,13 @@ parse_authorized_key_file(const char *us - strncat(hostname, fqdn, strcspn(fqdn, ".")); - #endif - authorized_keys_file = -- pamsshagentauth_percent_expand(auth_keys_file_buf, "h", -+ percent_expand(auth_keys_file_buf, "h", - getpwnam(user)->pw_dir, "H", hostname, - "f", fqdn, "u", user, NULL); - } - - int --pam_user_key_allowed(const char *ruser, Key * key) -+pam_user_key_allowed(const char *ruser, struct sshkey * key) - { - return - pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h 2020-09-23 10:52:16.424001475 +0200 -@@ -32,7 +32,7 @@ - #define _PAM_USER_KEY_ALLOWED_H - - #include "identity.h" --int pam_user_key_allowed(const char *, Key *); -+int pam_user_key_allowed(const char *, struct sshkey *); - void parse_authorized_key_file(const char *, const char *); - - #endif -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c 2020-09-23 10:52:16.424001475 +0200 -@@ -45,44 +45,46 @@ - #include "xmalloc.h" - #include "ssh.h" - #include "ssh2.h" --#include "buffer.h" -+#include "sshbuf.h" - #include "log.h" - #include "compat.h" --#include "key.h" -+#include "digest.h" -+#include "sshkey.h" - #include "pathnames.h" - #include "misc.h" - #include "secure_filename.h" - #include "uidswap.h" -- --#include "identity.h" -+#include - - /* return 1 if user allows given key */ - /* Modified slightly from original found in auth2-pubkey.c */ - static int --pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key) -+pamsshagentauth_check_authkeys_file(FILE * f, char *file, struct sshkey * key) - { -- char line[SSH_MAX_PUBKEY_BYTES]; -+ char *line = NULL; - int found_key = 0; - u_long linenum = 0; -- Key *found; -+ struct sshkey *found; - char *fp; -+ size_t linesize = 0; - - found_key = 0; -- found = pamsshagentauth_key_new(key->type); -+ found = sshkey_new(key->type); - -- while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { -+ while ((getline(&line, &linesize, f)) != -1) { - char *cp = NULL; /* *key_options = NULL; */ - -+ linenum++; - /* Skip leading whitespace, empty and comment lines. */ - for(cp = line; *cp == ' ' || *cp == '\t'; cp++); - if(!*cp || *cp == '\n' || *cp == '#') - continue; - -- if(pamsshagentauth_key_read(found, &cp) != 1) { -+ if (sshkey_read(found, &cp) != 0) { - /* no key? check if there are options for this key */ - int quoted = 0; - -- pamsshagentauth_verbose("user_key_allowed: check options: '%s'", cp); -+ verbose("user_key_allowed: check options: '%s'", cp); - /* key_options = cp; */ - for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { - if(*cp == '\\' && cp[1] == '"') -@@ -92,26 +94,27 @@ pamsshagentauth_check_authkeys_file(FILE - } - /* Skip remaining whitespace. */ - for(; *cp == ' ' || *cp == '\t'; cp++); -- if(pamsshagentauth_key_read(found, &cp) != 1) { -- pamsshagentauth_verbose("user_key_allowed: advance: '%s'", cp); -+ if(sshkey_read(found, &cp) != 0) { -+ verbose("user_key_allowed: advance: '%s'", cp); - /* still no key? advance to next line */ - continue; - } - } -- if(pamsshagentauth_key_equal(found, key)) { -+ if(sshkey_equal(found, key)) { - found_key = 1; -- pamsshagentauth_logit("matching key found: file/command %s, line %lu", file, -+ logit("matching key found: file/command %s, line %lu", file, - linenum); -- fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -- pamsshagentauth_logit("Found matching %s key: %s", -- pamsshagentauth_key_type(found), fp); -- pamsshagentauth_xfree(fp); -+ fp = sshkey_fingerprint(found, SSH_DIGEST_SHA256, SSH_FP_BASE64); -+ logit("Found matching %s key: %s", -+ sshkey_type(found), fp); -+ free(fp); - break; - } - } -- pamsshagentauth_key_free(found); -+ free(line); -+ sshkey_free(found); - if(!found_key) -- pamsshagentauth_verbose("key not found"); -+ verbose("key not found"); - return found_key; - } - -@@ -120,19 +123,19 @@ pamsshagentauth_check_authkeys_file(FILE - * returns 1 if the key is allowed or 0 otherwise. - */ - int --pamsshagentauth_user_key_allowed2(struct passwd *pw, Key * key, char *file) -+pamsshagentauth_user_key_allowed2(struct passwd *pw, struct sshkey * key, char *file) - { - FILE *f; - int found_key = 0; - struct stat st; -- char buf[SSH_MAX_PUBKEY_BYTES]; -+ char buf[256]; - - /* Temporarily use the user's uid. */ -- pamsshagentauth_verbose("trying public key file %s", file); -+ verbose("trying public key file %s", file); - - /* Fail not so quietly if file does not exist */ - if(stat(file, &st) < 0) { -- pamsshagentauth_verbose("File not found: %s", file); -+ verbose("File not found: %s", file); - return 0; - } - -@@ -144,7 +147,7 @@ pamsshagentauth_user_key_allowed2(struct - - if(pamsshagentauth_secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { - fclose(f); -- pamsshagentauth_logit("Authentication refused: %s", buf); -+ logit("Authentication refused: %s", buf); - return 0; - } - -@@ -160,7 +163,7 @@ pamsshagentauth_user_key_allowed2(struct - int - pamsshagentauth_user_key_command_allowed2(char *authorized_keys_command, - char *authorized_keys_command_user, -- struct passwd *user_pw, Key * key) -+ struct passwd *user_pw, struct sshkey * key) - { - FILE *f; - int ok, found_key = 0; -@@ -187,44 +190,44 @@ pamsshagentauth_user_key_command_allowed - else { - pw = getpwnam(authorized_keys_command_user); - if(pw == NULL) { -- pamsshagentauth_logerror("authorized_keys_command_user \"%s\" not found: %s", -+ error("authorized_keys_command_user \"%s\" not found: %s", - authorized_keys_command_user, strerror(errno)); - return 0; - } - } - -- pamsshagentauth_temporarily_use_uid(pw); -+ temporarily_use_uid(pw); - - if(stat(authorized_keys_command, &st) < 0) { -- pamsshagentauth_logerror -+ error - ("Could not stat AuthorizedKeysCommand \"%s\": %s", - authorized_keys_command, strerror(errno)); - goto out; - } - if(pamsshagentauth_auth_secure_path - (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { -- pamsshagentauth_logerror("Unsafe AuthorizedKeysCommand: %s", errmsg); -+ error("Unsafe AuthorizedKeysCommand: %s", errmsg); - goto out; - } - - /* open the pipe and read the keys */ - if(pipe(p) != 0) { -- pamsshagentauth_logerror("%s: pipe: %s", __func__, strerror(errno)); -+ error("%s: pipe: %s", __func__, strerror(errno)); - goto out; - } - -- pamsshagentauth_debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", -+ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", - authorized_keys_command, pw->pw_name, username); - - /* - * Don't want to call this in the child, where it can fatal() and - * run cleanup_exit() code. - */ -- pamsshagentauth_restore_uid(); -+ restore_uid(); - - switch ((pid = fork())) { - case -1: /* error */ -- pamsshagentauth_logerror("%s: fork: %s", __func__, strerror(errno)); -+ error("%s: fork: %s", __func__, strerror(errno)); - close(p[0]); - close(p[1]); - return 0; -@@ -234,13 +237,13 @@ pamsshagentauth_user_key_command_allowed - - /* do this before the setresuid so thta they can be logged */ - if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { -- pamsshagentauth_logerror("%s: open %s: %s", __func__, _PATH_DEVNULL, -+ error("%s: open %s: %s", __func__, _PATH_DEVNULL, - strerror(errno)); - _exit(1); - } - if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1 - || dup2(devnull, STDERR_FILENO) == -1) { -- pamsshagentauth_logerror("%s: dup2: %s", __func__, strerror(errno)); -+ error("%s: dup2: %s", __func__, strerror(errno)); - _exit(1); - } - #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) -@@ -248,7 +251,7 @@ pamsshagentauth_user_key_command_allowed - #else - if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { - #endif -- pamsshagentauth_logerror("setresgid %u: %s", (u_int) pw->pw_gid, -+ error("setresgid %u: %s", (u_int) pw->pw_gid, - strerror(errno)); - _exit(1); - } -@@ -258,7 +261,7 @@ pamsshagentauth_user_key_command_allowed - #else - if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { - #endif -- pamsshagentauth_logerror("setresuid %u: %s", (u_int) pw->pw_uid, -+ error("setresuid %u: %s", (u_int) pw->pw_uid, - strerror(errno)); - _exit(1); - } -@@ -270,18 +273,18 @@ pamsshagentauth_user_key_command_allowed - - /* pretty sure this will barf because we are now suid, but since we - should't reach this anyway, I'll leave it here */ -- pamsshagentauth_logerror("AuthorizedKeysCommand %s exec failed: %s", -+ error("AuthorizedKeysCommand %s exec failed: %s", - authorized_keys_command, strerror(errno)); - _exit(127); - default: /* parent */ - break; - } - -- pamsshagentauth_temporarily_use_uid(pw); -+ temporarily_use_uid(pw); - - close(p[1]); - if((f = fdopen(p[0], "r")) == NULL) { -- pamsshagentauth_logerror("%s: fdopen: %s", __func__, strerror(errno)); -+ error("%s: fdopen: %s", __func__, strerror(errno)); - close(p[0]); - /* Don't leave zombie child */ - while(waitpid(pid, NULL, 0) == -1 && errno == EINTR); -@@ -292,22 +295,22 @@ pamsshagentauth_user_key_command_allowed - - while(waitpid(pid, &status, 0) == -1) { - if(errno != EINTR) { -- pamsshagentauth_logerror("%s: waitpid: %s", __func__, -+ error("%s: waitpid: %s", __func__, - strerror(errno)); - goto out; - } - } - if(WIFSIGNALED(status)) { -- pamsshagentauth_logerror("AuthorizedKeysCommand %s exited on signal %d", -+ error("AuthorizedKeysCommand %s exited on signal %d", - authorized_keys_command, WTERMSIG(status)); - goto out; - } else if(WEXITSTATUS(status) != 0) { -- pamsshagentauth_logerror("AuthorizedKeysCommand %s returned status %d", -+ error("AuthorizedKeysCommand %s returned status %d", - authorized_keys_command, WEXITSTATUS(status)); - goto out; - } - found_key = ok; - out: -- pamsshagentauth_restore_uid(); -+ restore_uid(); - return found_key; - } -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h 2020-09-23 10:52:16.424001475 +0200 -@@ -32,7 +32,7 @@ - #define _PAM_USER_KEY_ALLOWED_H - - #include "identity.h" --int pamsshagentauth_user_key_allowed2(struct passwd *, Key *, char *); --int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, Key *); -+int pamsshagentauth_user_key_allowed2(struct passwd *, struct sshkey *, char *); -+int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, struct sshkey *); - - #endif -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c 2020-09-23 10:52:16.424001475 +0200 -@@ -53,8 +53,8 @@ - #include "xmalloc.h" - #include "match.h" - #include "log.h" --#include "buffer.h" --#include "key.h" -+#include "sshbuf.h" -+#include "sshkey.h" - #include "misc.h" - - -@@ -80,7 +80,7 @@ pamsshagentauth_auth_secure_path(const c - int comparehome = 0; - struct stat st; - -- pamsshagentauth_verbose("auth_secure_filename: checking for uid: %u", uid); -+ verbose("auth_secure_filename: checking for uid: %u", uid); - - if (realpath(name, buf) == NULL) { - snprintf(err, errlen, "realpath %s failed: %s", name, -@@ -115,9 +115,9 @@ pamsshagentauth_auth_secure_path(const c - snprintf(err, errlen, "dirname() failed"); - return -1; - } -- pamsshagentauth_strlcpy(buf, cp, sizeof(buf)); -+ strlcpy(buf, cp, sizeof(buf)); - -- pamsshagentauth_verbose("secure_filename: checking '%s'", buf); -+ verbose("secure_filename: checking '%s'", buf); - if (stat(buf, &st) < 0 || - (st.st_uid != 0 && st.st_uid != uid) || - (st.st_mode & 022) != 0) { -@@ -128,7 +128,7 @@ pamsshagentauth_auth_secure_path(const c - - /* If are passed the homedir then we can stop */ - if (comparehome && strcmp(homedir, buf) == 0) { -- pamsshagentauth_verbose("secure_filename: terminating check at '%s'", -+ verbose("secure_filename: terminating check at '%s'", - buf); - break; - } -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2020-09-23 10:52:16.424001475 +0200 -@@ -37,10 +37,11 @@ - #include "xmalloc.h" - #include "ssh.h" - #include "ssh2.h" --#include "buffer.h" -+#include "sshbuf.h" - #include "log.h" - #include "compat.h" --#include "key.h" -+#include "sshkey.h" -+#include "ssherr.h" - #include "pathnames.h" - #include "misc.h" - #include "secure_filename.h" -@@ -48,54 +49,59 @@ - #include "identity.h" - #include "pam_user_authorized_keys.h" - -+#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54 -+ - /* extern u_char *session_id2; - extern uint8_t session_id_len; - */ - - int --userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) -+userauth_pubkey_from_id(const char *ruser, Identity * id, struct sshbuf * session_id2) - { -- Buffer b = { 0 }; -+ struct sshbuf *b = NULL; - char *pkalg = NULL; - u_char *pkblob = NULL, *sig = NULL; -- u_int blen = 0, slen = 0; -- int authenticated = 0; -+ size_t blen = 0, slen = 0; -+ int r, authenticated = 0; - -- pkalg = (char *) key_ssh_name(id->key); -+ pkalg = (char *) sshkey_ssh_name(id->key); - - /* first test if this key is even allowed */ - if(! pam_user_key_allowed(ruser, id->key)) -- goto user_auth_clean_exit; -+ goto user_auth_clean_exit_without_buffer; - -- if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) -- goto user_auth_clean_exit; -+ if(sshkey_to_blob(id->key, &pkblob, &blen) != 0) -+ goto user_auth_clean_exit_without_buffer; - - /* construct packet to sign and test */ -- pamsshagentauth_buffer_init(&b); -+ if ((b = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); - -- pamsshagentauth_buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset); -- pamsshagentauth_buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); -- pamsshagentauth_buffer_put_cstring(&b, ruser); -- pamsshagentauth_buffer_put_cstring(&b, "pam_ssh_agent_auth"); -- pamsshagentauth_buffer_put_cstring(&b, "publickey"); -- pamsshagentauth_buffer_put_char(&b, 1); -- pamsshagentauth_buffer_put_cstring(&b, pkalg); -- pamsshagentauth_buffer_put_string(&b, pkblob, blen); -+ if ((r = sshbuf_put_string(b, sshbuf_ptr(session_id2), sshbuf_len(session_id2))) != 0 || -+ (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_TRUST_REQUEST)) != 0 || -+ (r = sshbuf_put_cstring(b, ruser)) != 0 || -+ (r = sshbuf_put_cstring(b, "pam_ssh_agent_auth")) != 0 || -+ (r = sshbuf_put_cstring(b, "publickey")) != 0 || -+ (r = sshbuf_put_u8(b, 1)) != 0 || -+ (r = sshbuf_put_cstring(b, pkalg)) != 0 || -+ (r = sshbuf_put_string(b, pkblob, blen)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - -- if(ssh_agent_sign(id->ac, id->key, &sig, &slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) != 0) -+ if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) - goto user_auth_clean_exit; - - /* test for correct signature */ -- if(pamsshagentauth_key_verify(id->key, sig, slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) == 1) -+ if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) - authenticated = 1; - - user_auth_clean_exit: - /* if(&b != NULL) */ -- pamsshagentauth_buffer_free(&b); -+ sshbuf_free(b); -+ user_auth_clean_exit_without_buffer: - if(sig != NULL) -- pamsshagentauth_xfree(sig); -+ free(sig); - if(pkblob != NULL) -- pamsshagentauth_xfree(pkblob); -+ free(pkblob); - CRYPTO_cleanup_all_ex_data(); - return authenticated; - } -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h 2020-09-23 10:52:16.424001475 +0200 -@@ -31,7 +31,7 @@ - #ifndef _USERAUTH_PUBKEY_FROM_ID_H - #define _USERAUTH_PUBKEY_FROM_ID_H - --#include --int userauth_pubkey_from_id(const char *, Identity *, Buffer *); -+#include "identity.h" -+int userauth_pubkey_from_id(const char *, Identity *, struct sshbuf *); - - #endif -diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c 2020-09-23 10:52:16.424001475 +0200 -@@ -56,7 +56,7 @@ pamsshagentauth_uudecode(const char *src - /* and remove trailing whitespace because __b64_pton needs this */ - *p = '\0'; - len = pamsshagentauth___b64_pton(encoded, target, targsize); -- pamsshagentauth_xfree(encoded); -+ xfree(encoded); - return len; - } - -@@ -70,7 +70,7 @@ pamsshagentauth_dump_base64(FILE *fp, co - fprintf(fp, "dump_base64: len > 65536\n"); - return; - } -- buf = pamsshagentauth_xmalloc(2*len); -+ buf = malloc(2*len); - n = pamsshagentauth_uuencode(data, len, buf, 2*len); - for (i = 0; i < n; i++) { - fprintf(fp, "%c", buf[i]); -@@ -79,5 +79,5 @@ pamsshagentauth_dump_base64(FILE *fp, co - } - if (i % 70 != 69) - fprintf(fp, "\n"); -- pamsshagentauth_xfree(buf); -+ free(buf); - } ---- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c.compat 2020-09-23 11:32:30.783695267 +0200 -+++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c 2020-09-23 11:33:21.383389036 +0200 -@@ -33,7 +33,8 @@ - #include - - #include "defines.h" --#include "key.h" -+#include -+#include "sshkey.h" - #include "log.h" - - #include "pam_user_authorized_keys.h" -@@ -42,28 +42,28 @@ - int authenticated = 0; - const char method[] = "publickey "; - -- char* ai = pamsshagentauth_xstrdup(ssh_auth_info); -+ char* ai = xstrdup(ssh_auth_info); - char* saveptr; - - char* auth_line = strtok_r(ai, "\n", &saveptr); - while (auth_line != NULL) { - if (strncmp(auth_line, method, sizeof(method) - 1) == 0) { - char* key_str = auth_line + sizeof(method) - 1; -- Key* key = pamsshagentauth_key_new(KEY_UNSPEC); -+ struct sshkey* key = sshkey_new(KEY_UNSPEC); - if (key == NULL) { - continue; - } -- int r = pamsshagentauth_key_read(key, &key_str); -+ int r = sshkey_read(key, &key_str); - if (r == 1) { - if (pam_user_key_allowed(ruser, key)) { - authenticated = 1; -- pamsshagentauth_key_free(key); -+ sshkey_free(key); - break; - } - } else { -- pamsshagentauth_verbose("Failed to create key for %s: %d", auth_line, r); -+ verbose("Failed to create key for %s: %d", auth_line, r); - } -- pamsshagentauth_key_free(key); -+ sshkey_free(key); - } - auth_line = strtok_r(NULL, "\n", &saveptr); - } diff --git a/pam_ssh_agent_auth-0.10.2-dereference.patch b/pam_ssh_agent_auth-0.10.2-dereference.patch deleted file mode 100644 index bf49c37..0000000 --- a/pam_ssh_agent_auth-0.10.2-dereference.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c ---- a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c -+++ b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c -@@ -158,11 +158,12 @@ parse_authorized_key_file(const char *user, - int - pam_user_key_allowed(const char *ruser, struct sshkey * key) - { -+ struct passwd *pw; - return -- pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), -- key, authorized_keys_file) -- || pamsshagentauth_user_key_allowed2(getpwuid(0), key, -- authorized_keys_file) -+ ( (pw = getpwuid(authorized_keys_file_allowed_owner_uid)) && -+ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) -+ || ((pw = getpwuid(0)) && -+ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) - || pamsshagentauth_user_key_command_allowed2(authorized_keys_command, - authorized_keys_command_user, - getpwnam(ruser), key); diff --git a/pam_ssh_agent_auth-0.10.3-seteuid.patch b/pam_ssh_agent_auth-0.10.3-seteuid.patch deleted file mode 100644 index be1f8e5..0000000 --- a/pam_ssh_agent_auth-0.10.3-seteuid.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid 2017-02-07 15:41:53.172334151 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 15:41:53.174334149 +0100 -@@ -238,17 +238,26 @@ ssh_get_authentication_socket_for_uid(ui - } - - errno = 0; -- seteuid(uid); /* To ensure a race condition is not used to circumvent the stat -- above, we will temporarily drop UID to the caller */ -- if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { -+ /* To ensure a race condition is not used to circumvent the stat -+ above, we will temporarily drop UID to the caller */ -+ if (seteuid(uid) == -1) { - close(sock); -- if(errno == EACCES) -- fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); -+ error("seteuid(%lu) failed with error: %s", -+ (unsigned long) uid, strerror(errno)); - return -1; - } -+ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { -+ close(sock); -+ sock = -1; -+ if(errno == EACCES) -+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); -+ } - -- seteuid(0); /* we now continue the regularly scheduled programming */ -- -+ /* we now continue the regularly scheduled programming */ -+ if (0 != seteuid(0)) { -+ fatal("setuid(0) failed with error: %s", strerror(errno)); -+ return -1; -+ } - return sock; - } - diff --git a/pam_ssh_agent_auth-0.10.4-rsasha2.patch b/pam_ssh_agent_auth-0.10.4-rsasha2.patch deleted file mode 100644 index c8815bb..0000000 --- a/pam_ssh_agent_auth-0.10.4-rsasha2.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -up openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c ---- openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 2022-07-15 15:08:12.865585410 +0200 -+++ openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2022-07-15 15:16:25.164282372 +0200 -@@ -87,8 +87,13 @@ userauth_pubkey_from_id(const char *ruse - (r = sshbuf_put_string(b, pkblob, blen)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - -- if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) -- goto user_auth_clean_exit; -+ if (sshkey_type_plain(id->key->type) == KEY_RSA -+ && ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), "rsa-sha2-256", 0) == 0) { -+ /* Do nothing */ -+ } else { -+ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) -+ goto user_auth_clean_exit; -+ } - - /* test for correct signature */ - if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) diff --git a/pam_ssh_agent_auth-0.9.2-visibility.patch b/pam_ssh_agent_auth-0.9.2-visibility.patch deleted file mode 100644 index aea068d..0000000 --- a/pam_ssh_agent_auth-0.9.2-visibility.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -up openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c ---- openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility 2014-03-31 19:35:17.000000000 +0200 -+++ openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c 2016-01-22 15:22:40.984469774 +0100 -@@ -72,7 +72,7 @@ char *__progname; - extern char *__progname; - #endif - --PAM_EXTERN int -+PAM_EXTERN int __attribute__ ((visibility ("default"))) - pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) - { - char **argv_ptr; -@@ -214,7 +214,7 @@ cleanexit: - } - - --PAM_EXTERN int -+PAM_EXTERN int __attribute__ ((visibility ("default"))) - pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) - { - UNUSED(pamh); diff --git a/pam_ssh_agent_auth-0.9.3-agent_structure.patch b/pam_ssh_agent_auth-0.9.3-agent_structure.patch deleted file mode 100644 index 1f2c02c..0000000 --- a/pam_ssh_agent_auth-0.9.3-agent_structure.patch +++ /dev/null @@ -1,96 +0,0 @@ -diff -up openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/identity.h ---- openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent 2016-11-13 04:24:32.000000000 +0100 -+++ openssh/pam_ssh_agent_auth-0.10.3/identity.h 2017-09-27 14:25:49.421739027 +0200 -@@ -38,6 +38,12 @@ - typedef struct identity Identity; - typedef struct idlist Idlist; - -+typedef struct { -+ int fd; -+ struct sshbuf *identities; -+ int howmany; -+} AuthenticationConnection; -+ - struct identity { - TAILQ_ENTRY(identity) next; - AuthenticationConnection *ac; /* set if agent supports key */ -diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c ---- openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 -+++ openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-09-27 14:25:49.421739027 +0200 -@@ -39,6 +39,7 @@ - #include "sshbuf.h" - #include "sshkey.h" - #include "authfd.h" -+#include "ssherr.h" - #include - #include - #include "ssh2.h" -@@ -291,36 +292,43 @@ pamsshagentauth_find_authorized_keys(con - { - struct sshbuf *session_id2 = NULL; - Identity *id; -- struct sshkey *key; - AuthenticationConnection *ac; -- char *comment; - uint8_t retval = 0; - uid_t uid = getpwnam(ruser)->pw_uid; -+ struct ssh_identitylist *idlist; -+ int r; -+ unsigned int i; - - OpenSSL_add_all_digests(); - pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); - - if ((ac = ssh_get_authentication_connection_for_uid(uid))) { - verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); -- for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) -- { -- if(key != NULL) { -+ if ((r = ssh_fetch_identitylist(ac->fd, &idlist)) != 0) { -+ if (r != SSH_ERR_AGENT_NO_IDENTITIES) -+ fprintf(stderr, "error fetching identities for " -+ "protocol %d: %s\n", 2, ssh_err(r)); -+ } else { -+ for (i = 0; i < idlist->nkeys; i++) -+ { -+ if (idlist->keys[i] != NULL) { - id = xcalloc(1, sizeof(*id)); -- id->key = key; -- id->filename = comment; -+ id->key = idlist->keys[i]; -+ id->filename = idlist->comments[i]; - id->ac = ac; - if(userauth_pubkey_from_id(ruser, id, session_id2)) { - retval = 1; - } -- free(id->filename); -- key_free(id->key); - free(id); - if(retval == 1) - break; -- } -- } -+ } -+ } -- sshbuf_free(session_id2); -- ssh_close_authentication_connection(ac); -+ sshbuf_free(session_id2); -+ ssh_free_identitylist(idlist); -+ } -+ ssh_close_authentication_socket(ac->fd); -+ free(ac); - } - else { - verbose("No ssh-agent could be contacted"); -diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c ---- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 -+++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-09-27 14:25:49.422739032 +0200 -@@ -84,7 +85,7 @@ userauth_pubkey_from_id(const char *ruse - (r = sshbuf_put_string(b, pkblob, blen)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - -- if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) -+ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) - goto user_auth_clean_exit; - - /* test for correct signature */ diff --git a/pam_ssh_agent_auth-0.9.3-build.patch b/pam_ssh_agent_auth-0.9.3-build.patch deleted file mode 100644 index 4018c4d..0000000 --- a/pam_ssh_agent_auth-0.9.3-build.patch +++ /dev/null @@ -1,198 +0,0 @@ -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 14:29:41.626116675 +0100 -@@ -43,12 +43,31 @@ - #include - #include "ssh2.h" - #include "misc.h" -+#include "ssh.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - - #include "userauth_pubkey_from_id.h" - #include "identity.h" - #include "get_command_line.h" - extern char **environ; - -+/* -+ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user -+ * A cursory check is done, but to avoid race conditions, it is necessary -+ * to drop effective UID when connecting to the socket. -+ * -+ * If the cause of error is EACCES, because we verified we would not have that -+ * problem initially, we can safely assume that somebody is attempting to find a -+ * race condition; so a more "direct" log message is generated. -+ */ -+ - static char * - log_action(char ** action, size_t count) - { -@@ -85,7 +104,7 @@ void - pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, - const char * ruser, const char * servicename) - { -- char *cookie = NULL; -+ u_char *cookie = NULL; - uint8_t i = 0; - uint32_t rnd = 0; - uint8_t cookie_len; -@@ -112,7 +131,7 @@ pamsshagentauth_session_id2_gen(Buffer * - if (i % 4 == 0) { - rnd = pamsshagentauth_arc4random(); - } -- cookie[i] = (char) rnd; -+ cookie[i] = (u_char) rnd; - rnd >>= 8; - } - -@@ -177,6 +196,86 @@ pamsshagentauth_session_id2_gen(Buffer * - } - - int -+ssh_get_authentication_socket_for_uid(uid_t uid) -+{ -+ const char *authsocket; -+ int sock; -+ struct sockaddr_un sunaddr; -+ struct stat sock_st; -+ -+ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); -+ if (!authsocket) -+ return -1; -+ -+ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ -+ if( stat(authsocket,&sock_st) == 0) { -+ if(uid != 0 && sock_st.st_uid != uid) { -+ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); -+ return -1; -+ } -+ } -+ -+ /* -+ * Ensures that the EACCES tested for below can _only_ happen if somebody -+ * is attempting to race the stat above to bypass authentication. -+ */ -+ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { -+ error("ssh-agent socket has incorrect permissions for owner"); -+ return -1; -+ } -+ -+ sunaddr.sun_family = AF_UNIX; -+ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); -+ -+ sock = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sock < 0) -+ return -1; -+ -+ /* close on exec */ -+ if (fcntl(sock, F_SETFD, 1) == -1) { -+ close(sock); -+ return -1; -+ } -+ -+ errno = 0; -+ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat -+ above, we will temporarily drop UID to the caller */ -+ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { -+ close(sock); -+ if(errno == EACCES) -+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); -+ return -1; -+ } -+ -+ seteuid(0); /* we now continue the regularly scheduled programming */ -+ -+ return sock; -+} -+ -+AuthenticationConnection * -+ssh_get_authentication_connection_for_uid(uid_t uid) -+{ -+ AuthenticationConnection *auth; -+ int sock; -+ -+ sock = ssh_get_authentication_socket_for_uid(uid); -+ -+ /* -+ * Fail if we couldn't obtain a connection. This happens if we -+ * exited due to a timeout. -+ */ -+ if (sock < 0) -+ return NULL; -+ -+ auth = xmalloc(sizeof(*auth)); -+ auth->fd = sock; -+ buffer_init(&auth->identities); -+ auth->howmany = 0; -+ -+ return auth; -+} -+ -+int - pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) - { - Buffer session_id2 = { 0 }; -@@ -190,7 +289,7 @@ pamsshagentauth_find_authorized_keys(con - OpenSSL_add_all_digests(); - pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); - -- if ((ac = ssh_get_authentication_connection(uid))) { -+ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { - pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); - for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) - { -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in 2017-02-07 14:40:14.407566921 +0100 -@@ -52,7 +52,7 @@ PATHS= - CC=@CC@ - LD=@LD@ - CFLAGS=@CFLAGS@ --CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -+CPPFLAGS=-I.. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ - LIBS=@LIBS@ - AR=@AR@ - AWK=@AWK@ -@@ -61,8 +61,8 @@ INSTALL=@INSTALL@ - PERL=@PERL@ - SED=@SED@ - ENT=@ENT@ --LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ --LDFLAGS_SHARED = @LDFLAGS_SHARED@ -+LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ -+LDFLAGS_SHARED =-Wl,-z,defs @LDFLAGS_SHARED@ - EXEEXT=@EXEEXT@ - - INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ -@@ -74,7 +74,7 @@ SSHOBJS=xmalloc.o atomicio.o authfd.o bu - - ED25519OBJS=ed25519-donna/ed25519.o - --PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o -+PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o secure_filename.o - - - MANPAGES_IN = pam_ssh_agent_auth.pod -@@ -94,13 +94,13 @@ $(PAM_MODULES): Makefile.in config.h - .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ - --LIBCOMPAT=openbsd-compat/libopenbsd-compat.a -+LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a - $(LIBCOMPAT): always - (cd openbsd-compat && $(MAKE)) - always: - --pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o -- $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam -+pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o ../uidswap.o ../ssh-sk-client.o -+ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) ../ssh-sk-client.o $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o ../uidswap.o $(LIBS) -lpam - - $(MANPAGES): $(MANPAGES_IN) - pod2man --section=8 --release=v0.10.3 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 diff --git a/parallel_test.Makefile b/parallel_test.Makefile new file mode 100644 index 0000000..f49df30 --- /dev/null +++ b/parallel_test.Makefile @@ -0,0 +1,14 @@ +# just a Makefile parallel_test.sh uses to run stuff in parallel with make +%: + $(MAKE) -j1 -C .t/$* $* + +t-exec-%: + $(MAKE) -j1 -C ".t/t-exec-$*" \ + TEST_SSH_PORT=10$*0 \ + SKIP_LTESTS="$(shell cat .ltests/not-in/$*)" \ + BUILDDIR="$(shell pwd)/.t/t-exec-$*" \ + TEST_SHELL=sh \ + MAKE=make \ + TEST_SSH_TRACE=yes \ + TEST_SSH_FAIL_FATAL=yes \ + t-exec \ diff --git a/parallel_test.sh b/parallel_test.sh new file mode 100755 index 0000000..682c7e8 --- /dev/null +++ b/parallel_test.sh @@ -0,0 +1,91 @@ +#!/usr/bin/bash +set -uexo pipefail + +# The custom %check script to run the OpenSSH upstream testsuite in parallel. +# +# The upstream testsuite is serial, +# so the idea here is to split the testsuite into several $PARTS: +# * file-tests +# * interop-tests +# * unit +# * ltests-00 +# * ltests-01 +# * ... +# * ltests-23 +# and run them in parallel, using make, each in its own build subtree. + +PARALLEL_MAKEFILE=$1 + +SPLIT=24 +PARTS='file-tests interop-tests unit ' +for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i); + PARTS+="t-exec-$ii " +done + +# work around a selinux restriction: +chcon -t unconfined_exec_t ssh-sk-helper || : + +# work around something else that only crops up in brew +export TEST_SSH_UNSAFE_PERMISSIONS=1 + +# create a .test directory to store all our files in: +mkdir -p .t .ltests/{in,not-in} + +# patch testsuite: use different ports to avoid port collisions +grep -REi 'port=[2-9][0-9]*' regress +sed -i 's|PORT=4242|PORT=$(expr $TEST_SSH_PORT + 1)|' \ + regress/test-exec.sh* +sed -i 's|^P=3301 # test port|P=$(expr $TEST_SSH_PORT + 1)|' \ + regress/multiplex.sh* +sed -i 's|^fwdport=3301|fwdport=$(expr $TEST_SSH_PORT + 1)|' \ + regress/cfgmatch.sh* regress/cfgmatchlisten.sh* +sed -i 's|^LFWD_PORT=.*|LFWD_PORT=$(expr $TEST_SSH_PORT + 1)|' \ + regress/forward-control.sh* +sed -i 's|^RFWD_PORT=.*|RFWD_PORT=$(expr $TEST_SSH_PORT + 2)|' \ + regress/forward-control.sh* +( ! grep -REi 'port=[2-9][0-9]*' regress) # try to find more of those + +# patch testsuite: speed up +sed -i 's|sleep 1$|sleep .25|' regress/forward-control.sh + +# extract LTESTS list to .tests/ltests/all: +grep -Ex 'tests:[[:space:]]*file-tests t-exec interop-tests extra-tests unit' Makefile +echo -ne '\necho-ltests:\n\techo ${LTESTS}' >> regress/Makefile +make -s -C regress echo-ltests | tr ' ' '\n' > .ltests/all + +# separate ltests into $SPLIT roughly equal .tests/ltests/in/$ii parts: +grep -qFx connect .ltests/all +( ! grep -qFx nonex .ltests/all ) +split -d -a2 --number=l/$SPLIT .ltests/all .ltests/in/ +wc -l .ltests/in/* +grep -qFx connect .ltests/in/* + +# generate the inverses of them --- .ltests/not-in/$ii: +( ! grep -qFx nonex .ltests/in/* ) +for ((i = 0; i < SPLIT; i++)); do ii=$(printf %02d $i); + while read -r tname; do + if ! grep -qFx "$tname" ".ltests/in/$ii"; then + echo -n "$tname " >> ".ltests/not-in/$ii" + fi + done < .ltests/all +done +grep . .ltests/not-in/* +( ! grep -q ^connect .ltests/not-in/0 ) +for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i); + grep -q ^connect .ltests/not-in/$ii +done + +# prepare several test directories: +for PART in $PARTS; do + mkdir .t/${PART} + cp -ra * .t/${PART}/ + sed -i "s|abs_top_srcdir=.*|abs_top_srcdir=$(pwd)/.t/${PART}|" \ + .t/${PART}/Makefile + sed -i "s|abs_top_builddir=.*|abs_top_builddir=$(pwd)/.t/${PART}|" \ + .t/${PART}/Makefile + sed -i "s|^BUILDDIR=.*|BUILDDIR=$(pwd)/.t/${PART}|" \ + .t/${PART}/Makefile +done + +# finally, run tests $PARTS in parallel in their own subtrees: +time make -f "$PARALLEL_MAKEFILE" -j$(nproc) $PARTS diff --git a/plans/main.fmf b/plans/main.fmf new file mode 100644 index 0000000..ae0c305 --- /dev/null +++ b/plans/main.fmf @@ -0,0 +1,6 @@ +summary: Run all tests +execute: + how: tmt +discover: + how: fmf + diff --git a/sources b/sources index 585760a..318e485 100644 --- a/sources +++ b/sources @@ -1,4 +1,3 @@ -SHA512 (openssh-9.3p1.tar.gz) = 087ff6fe5f6caab4c6c3001d906399e02beffad7277280f11187420c2939fd4befdcb14643862a657ce4cad2f115b82a0a1a2c99df6ee54dcd76b53647637c19 -SHA512 (openssh-9.3p1.tar.gz.asc) = 6222378eb24a445c6c1db255392b405f5369b1af0e92f558d4ba05b0d83ab0d084cb8f4b91d7ae8636f333d970638a6635e2bc7af885135dd34992d87f2ef1f4 -SHA512 (pam_ssh_agent_auth-0.10.4.tar.gz) = caccf72174d15e43f4c86a459ac6448682e62116557cf1e1e828955f3d1731595b238df42adec57860e7f341e92daf5d8285020bcb5018f3b8a5145aa32ee1c2 +SHA512 (openssh-10.2p1.tar.gz) = 66f3dd646179e71aaf41c33b6f14a207dc873d71d24f11c130a89dee317ee45398b818e5b94887b5913240964a38630d7bca3e481e0f1eff2e41d9e1cfdbdfc5 +SHA512 (openssh-10.2p1.tar.gz.asc) = f1f71700b1b0b2117aed505488b98b7ebb51ce26e53184b08df0b07aa2c5a1e54dc4d3cbcbe871b5ad849a2a0e22b02af318ff22a68c980ab53b04be03c9bf3c SHA512 (gpgkey-736060BA.gpg) = df44f3fdbcd1d596705348c7f5aed3f738c5f626a55955e0642f7c6c082995cf36a1b1891bb41b8715cb2aff34fef1c877e0eff0d3507dd00a055ba695757a21 diff --git a/ssh-agent.service b/ssh-agent.service index 812303c..d0c38dd 100644 --- a/ssh-agent.service +++ b/ssh-agent.service @@ -8,9 +8,7 @@ Documentation=man:ssh-agent(1) man:ssh-add(1) man:ssh(1) Requires=ssh-agent.socket [Service] -Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket -ExecStartPre=/usr/bin/rm -f $SSH_AUTH_SOCK -ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK +ExecStart=/usr/bin/ssh-agent -D PassEnvironment=SSH_AGENT_PID SuccessExitStatus=2 Type=simple diff --git a/sshd-keygen b/sshd-keygen index 170ada0..b15fc8c 100644 --- a/sshd-keygen +++ b/sshd-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/sshd-keygen@.service b/sshd-keygen@.service index f27f729..aee1303 100644 --- a/sshd-keygen@.service +++ b/sshd-keygen@.service @@ -4,6 +4,9 @@ ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key [Service] Type=oneshot +# Set option as empty variable to suppress warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/libexec/openssh/sshd-keygen %i diff --git a/sshd.service b/sshd.service index 0cb2a26..350624d 100644 --- a/sshd.service +++ b/sshd.service @@ -9,6 +9,9 @@ Wants=ssh-host-keys-migration.service [Service] Type=notify +# Set option as empty variable to suppress warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D $OPTIONS ExecReload=/bin/kill -HUP $MAINPID diff --git a/sshd.sysconfig b/sshd.sysconfig index a217ce7..be40d08 100644 --- a/sshd.sysconfig +++ b/sshd.sysconfig @@ -5,3 +5,7 @@ # example using systemctl enable sshd-keygen@dsa.service to allow creation # of DSA key or systemctl mask sshd-keygen@rsa.service to disable RSA key # creation. + +#SSH_RSA_BITS=3072 +#SSH_ECDSA_BITS=256 +OPTIONS="" diff --git a/sshd@.service b/sshd@.service index be6d3b9..4f12190 100644 --- a/sshd@.service +++ b/sshd@.service @@ -8,6 +8,10 @@ After=sshd-keygen.target Wants=ssh-host-keys-migration.service [Service] +# Set option as empty variable to avoid warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd -ExecStart=-/usr/sbin/sshd -i $OPTIONS +ExecStart=-/usr/sbin/sshd -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/tests/main.fmf b/tests/main.fmf new file mode 100644 index 0000000..339889b --- /dev/null +++ b/tests/main.fmf @@ -0,0 +1,11 @@ +test: ./runtest.sh +framework: beakerlib +require: + - iproute # needs ip command + - procps-ng # needs ps and pgrep commands + - initscripts # needs service command + - openssh-clients # needs ssh command + - findutils # needs find command + - net-tools # needs netstat command + - libselinux-utils # needs selinuxenabled command + - nmap-ncat # needs nc command diff --git a/tests/pam_ssh_agent_auth/Makefile b/tests/pam_ssh_agent_auth/Makefile index f77eb4d..7b75039 100644 --- a/tests/pam_ssh_agent_auth/Makefile +++ b/tests/pam_ssh_agent_auth/Makefile @@ -28,7 +28,7 @@ export TESTVERSION=1.0 BUILT_FILES= -FILES=$(METADATA) runtest.sh Makefile PURPOSE pam_save_ssh_var.c +FILES=$(METADATA) runtest.sh Makefile pam_save_ssh_var.c .PHONY: all install download clean diff --git a/tests/pam_ssh_agent_auth/PURPOSE b/tests/pam_ssh_agent_auth/PURPOSE deleted file mode 100644 index 59557de..0000000 --- a/tests/pam_ssh_agent_auth/PURPOSE +++ /dev/null @@ -1,7 +0,0 @@ -PURPOSE of /CoreOS/openssh/Sanity/pam_ssh_agent_auth -Description: This is basic sanity test for pam_ssh_agent_auth -Author: Jakub Jelen - -Created as a response to rhbz#1251777 and previous one rhbz#1225106. -The code of pam module is outdated and compiled with current openssh -version which went through quite enough refactoring. diff --git a/tests/pam_ssh_agent_auth/main.fmf b/tests/pam_ssh_agent_auth/main.fmf new file mode 100644 index 0000000..5820055 --- /dev/null +++ b/tests/pam_ssh_agent_auth/main.fmf @@ -0,0 +1,11 @@ +summary: Basic sanity test for pam_ssh_agent_auth +description: | + Created as a response to rhbz#1251777 and previous one rhbz#1225106. + The code of pam module is outdated and compiled with current openssh + version which went through quite enough refactoring. +contact: Jakub Jelen +require+: + - pam_ssh_agent_auth + - gcc # needs to test pam_ssh_agent_auth + - pam-devel # needs to test pam_ssh_agent_auth + - expect # needs to test pam_ssh_agent_auth diff --git a/tests/pam_ssh_agent_auth/runtest.sh b/tests/pam_ssh_agent_auth/runtest.sh index 297be39..7587269 100755 --- a/tests/pam_ssh_agent_auth/runtest.sh +++ b/tests/pam_ssh_agent_auth/runtest.sh @@ -26,7 +26,6 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Include Beaker environment -. /usr/bin/rhts-environment.sh || exit 1 . /usr/share/beakerlib/beakerlib.sh || exit 1 PACKAGE="openssh" @@ -48,6 +47,8 @@ rlJournalStart rlAssertRpm pam_ssh_agent_auth rlImport distribution/fips rlServiceStart sshd + # The following line is a temporary fix for https://pagure.io/releng/issue/12187 + rlRun "rpm --restore filesystem" rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" rlRun "cp ${PAM_MODULE}.c $TmpDir/" rlRun "pushd $TmpDir" @@ -62,10 +63,6 @@ auth sufficient pam_ssh_agent_auth.so file=$AUTH_KEYS' $PAM_SUDO" rlRun "echo $PASS |passwd --stdin $USER" rlPhaseEnd - if ! fipsIsEnabled; then - KEYS+=("dsa") - fi - for KEY in "${KEYS[@]}"; do rlPhaseStartTest "Test with key type $KEY" rlRun "su $USER -c 'ssh-keygen -t $KEY -f ~/.ssh/my_id_$KEY -N \"\"'" 0 @@ -179,6 +176,9 @@ _EOF rlRun "userdel -fr $USER" rlFileRestore rlServiceRestore sshd + # Collect journal data. If the test fails, the log probably + # explains why, which may be difficult to determine without logs. + rlRun "journalctl -b 0 > '$TMT_TEST_DATA'/journalctl.txt" rlPhaseEnd rlJournalPrintText rlJournalEnd diff --git a/tests/port-forwarding/Makefile b/tests/port-forwarding/Makefile index d325bdd..d92f24d 100644 --- a/tests/port-forwarding/Makefile +++ b/tests/port-forwarding/Makefile @@ -28,7 +28,7 @@ export TESTVERSION=1.0 BUILT_FILES= -FILES=$(METADATA) runtest.sh Makefile PURPOSE +FILES=$(METADATA) runtest.sh Makefile .PHONY: all install download clean diff --git a/tests/port-forwarding/PURPOSE b/tests/port-forwarding/PURPOSE deleted file mode 100644 index 5a8bc87..0000000 --- a/tests/port-forwarding/PURPOSE +++ /dev/null @@ -1,3 +0,0 @@ -PURPOSE of /CoreOS/openssh/Sanity/port-forwarding -Description: Testing port forwarding (ideally all possibilities: -L, -R, -D) -Author: Stanislav Zidek diff --git a/tests/port-forwarding/main.fmf b/tests/port-forwarding/main.fmf new file mode 100644 index 0000000..8f29286 --- /dev/null +++ b/tests/port-forwarding/main.fmf @@ -0,0 +1,4 @@ +summary: Testing port forwarding +description: | + Testing port forwarding (ideally all possibilities: -L, -R, -D) +contact: Stanislav Zidek diff --git a/tests/port-forwarding/runtest.sh b/tests/port-forwarding/runtest.sh index f18f2ae..d690270 100755 --- a/tests/port-forwarding/runtest.sh +++ b/tests/port-forwarding/runtest.sh @@ -44,6 +44,8 @@ rlJournalStart rlRun "su - $USER -c \"mkdir .ssh; chmod 700 .ssh; cd .ssh; ssh-keygen -N '' -f id_rsa; cat id_rsa.pub >authorized_keys; chmod 600 authorized_keys\"" rlRun "echo 'LogLevel DEBUG' >>/etc/ssh/sshd_config" rlServiceStart sshd + # Rate limit service restarts by sleeping + rlRun "sleep 3s" rlRun "IP=\$( ip a |grep 'scope global' |grep -w inet |cut -d'/' -f1 |awk '{ print \$2 }' |tail -1 )" rlRun "echo 'IP=$IP'" rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" @@ -98,6 +100,8 @@ forwarding_test() { rlRun "echo 'PermitOpen any' >>/etc/ssh/sshd_config" rlRun "echo '$IP anyhost1 anyhost2' >>/etc/hosts" rlRun "service sshd restart" + # Rate limit service restarts by sleeping + rlRun "sleep 3s" for i in `seq 3`; do forwarding_test "success" $FORWARDED anyhost1 $LISTEN forwarding_test "success" $FORWARDED anyhost2 $LISTEN @@ -114,6 +118,8 @@ forwarding_test() { rlRun "echo 'PermitOpen wildportallow:*' >>/etc/ssh/sshd_config" rlRun "echo '$IP wildportallow wildportdeny' >>/etc/hosts" rlRun "service sshd restart" + # Rate limit service restarts by sleeping + rlRun "sleep 3s" forwarding_test "success" $FORWARDED wildportallow $LISTEN ((FORWARDED+=1)) ((LISTEN+=1)) @@ -122,6 +128,8 @@ forwarding_test() { ((LISTEN+=1)) rlFileRestore --namespace port_wildcard rlRun "service sshd restart" + # Rate limit service restarts by sleeping + rlRun "sleep 3s" rlPhaseEnd fi @@ -131,6 +139,8 @@ forwarding_test() { rlRun "echo 'PermitOpen *:$LISTEN' >>/etc/ssh/sshd_config" rlRun "echo '$IP wildhost1 wildhost2' >>/etc/hosts" rlRun "service sshd restart" + # Rate limit service restarts by sleeping + rlRun "sleep 3s" forwarding_test "success" $FORWARDED wildhost1 $LISTEN ((FORWARDED+=1)) forwarding_test "success" $FORWARDED wildhost2 $LISTEN @@ -147,6 +157,9 @@ forwarding_test() { rlFileRestore rlServiceRestore sshd rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + # Collect journal data. If the test fails, the log probably + # explains why, which may be difficult to determine without logs. + rlRun "journalctl -b 0 > '$TMT_TEST_DATA'/journalctl.txt" rlPhaseEnd rlJournalPrintText rlJournalEnd diff --git a/tests/tests.yml b/tests/tests.yml deleted file mode 100644 index 8086af2..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -# Tests for docker container -- hosts: localhost - tags: - - container - # no compatible tests - -# Tests for classic environment and Atomic Host -- hosts: localhost - tags: - - all - - classic - - atomic - roles: - - role: standard-test-beakerlib - tests: - - port-forwarding - - pam_ssh_agent_auth - required_packages: - - iproute # needs ip command - - procps-ng # needs ps and pgrep commands - - initscripts # needs service command - - openssh-clients # needs ssh command - - findutils # needs find command - - net-tools # needs netstat command - - libselinux-utils # needs selinuxenabled command - - nmap-ncat # needs nc command - - pam_ssh_agent_auth - - gcc # needs to test pam_ssh_agent_auth - - pam-devel # needs to test pam_ssh_agent_auth - - expect # needs to test pam_ssh_agent_auth