From b.candler at pobox.com Thu Dec 5 05:47:08 2024 From: b.candler at pobox.com (Brian Candler) Date: Wed, 4 Dec 2024 18:47:08 +0000 Subject: Better reporting for signature algorithm mismatch? Message-ID: An issue that I come across from time to time is when I try to ssh into a box with an RSA key, and it fails because the target host is old and only does sha1 signatures.? However, the reason is not reported unless I turn on debugging. For example, all I see is: % ssh foo at bar foo at bar: Permission denied (publickey,keyboard-interactive). I find this confusing, since my first inclination is that the public key has not been installed properly on the target host. But if I remember to try again with debugging, then I see: % ssh -v foo at bar ... debug1: Will attempt key: /Users/brian/.ssh/id_rsa RSA SHA256:mVV81jWVCP/SDRFA7vRM/SDQniylCAcBoSERWyhAXEo agent ... debug1: Offering public key: /Users/brian/.ssh/id_rsa RSA SHA256:mVV81jWVCP/SDRFA7vRM/SDQniylCAcBoSERWyhAXEo agent debug1: send_pubkey_test: no mutual signature algorithm <<<< *THIS* ... debug1: Authentications that can continue: publickey,keyboard-interactive debug1: No more authentication methods to try. foo at bar: Permission denied (publickey,keyboard-interactive). % ssh -o PubkeyAcceptedAlgorithms=+ssh-rsa foo at bar << success >> I wonder if there could there be some way to highlight the "no mutual signature algorithm" message more prominently in normal operation? IMO it's not a problem with a specific key, but a protocol configuration issue which would affect *all* keys of that type.? Admittedly it is non-fatal, in the sense that other non-RSA keys or other auth methods can be tried, including falling back to password auth. Even then, I find it confusing to get a password prompt when I though I'd set up key authentication. Other, fatal protocol compatibility problems *do* get reported, e.g. Unable to negotiate with bar port 22: no matching key exchange method found. Their offer: diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 That's clear and explicit. However, because I'm so used to seeing this type of error when protocols don't match, it makes it more surprising that I don't see them for the ssh-rsa signature problem.? I'd like to see a warning for the first key tried, something like: Warning: unable to authenticate with rsa key: no mutual signature algorithm Their offer: ssh-rsa Our offer: rsa-sha2-256, rsa-sha2-512 Anyway, just an idea. Regards, Brian. From Jochen.Bern at binect.de Thu Dec 5 21:16:50 2024 From: Jochen.Bern at binect.de (Jochen Bern) Date: Thu, 5 Dec 2024 11:16:50 +0100 Subject: Better reporting for signature algorithm mismatch? In-Reply-To: References: Message-ID: On 04.12.24 19:47, Brian Candler wrote: > debug1: Offering public key: /Users/brian/.ssh/id_rsa RSA [...] > debug1: send_pubkey_test: no mutual signature algorithm <<<< *THIS* > > I wonder if there could there be some way to highlight the "no mutual > signature algorithm" message more prominently in normal operation? Wouldn't the extra output, even in cases where a different keypair succeeds later on, threaten to hose applications that expect the connection to be transparent (or fail completely)? As in, rsync, git, etc.? In general, the client may try a number of keypairs and every try has a number of possible reasons to fail, from cryptalgorithm-related ones (including "cipher (here: RSA) rejected" and "hash (here: SHA2 variant(s)) rejected") to "unknown keypair" to less-frequent ones (like "pubkey has a ForceCommand option and I can't execute that" etc.). I don't think that we should try to triage these cases into "interesting ones" that do emit a(n interim) warning, and the rest that doesn't. *If* the login fails *altogether*, however, doing a "post mortem" and adding a line to the effect of "oh, by the way, *one* of the keypairs failed only because of rare condition XY" could still be helpful. Kind regards, -- Jochen Bern Systemingenieur Binect GmbH -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 4336 bytes Desc: S/MIME Cryptographic Signature URL: From b.candler at pobox.com Thu Dec 5 22:45:27 2024 From: b.candler at pobox.com (Brian Candler) Date: Thu, 5 Dec 2024 11:45:27 +0000 Subject: Better reporting for signature algorithm mismatch? In-Reply-To: References: Message-ID: <5ade39c0-7efb-4702-bb00-a0f10cf99374@pobox.com> On 05/12/2024 10:16, Jochen Bern wrote: > ouldn't the extra output, even in cases where a different keypair > succeeds later on, threaten to hose applications that expect the > connection to be transparent (or fail completely)? As in, rsync, git, > etc.? > I don't think it would be a problem. There are many other cases where the ssh client inserts messages in normal operation, such as saying the host key is unknown and prompting you to accept it, or password/passphrase/keyboard-interactive authentication. Also, the remote host itself can generate extra messages on stderr: on a git push/pull for example, I often get messages such as what URL to use to make a merge request. Any reasonable client is going to pass these through. > *If* the login fails *altogether*, however, doing a "post mortem" and > adding a line to the effect of "oh, by the way, *one* of the keypairs > failed only because of rare condition XY" could still be helpful. That would be good enough. Something like "One or more keypairs could not be used because no mutual signature algorithm".? Ideally it would be shown *before* the password prompt when falling back to password auth after key auth has failed. From dbelyavs at redhat.com Mon Dec 9 21:04:29 2024 From: dbelyavs at redhat.com (Dmitry Belyavskiy) Date: Mon, 9 Dec 2024 11:04:29 +0100 Subject: PerSourcePenalties and ssh-copy-id Message-ID: Dear colleagues, Can we somehow improve the UX related to a relatively freshly introduced PerSourcePenalties option? A popular pattern implies installation of the users' keys to a freshly installed machine using ssh-copy-id script. The default settings don't allow this command to work normally and causes login failures. A reasonable workaround could be adding some threshold for a number of failures before the penalties are applied. -- Dmitry Belyavskiy From djm at mindrot.org Tue Dec 10 12:29:47 2024 From: djm at mindrot.org (Damien Miller) Date: Tue, 10 Dec 2024 12:29:47 +1100 (AEDT) Subject: PerSourcePenalties and ssh-copy-id In-Reply-To: References: Message-ID: On Mon, 9 Dec 2024, Dmitry Belyavskiy wrote: > Dear colleagues, > > Can we somehow improve the UX related to a relatively freshly > introduced PerSourcePenalties option? > > A popular pattern implies installation of the users' keys to a freshly > installed machine using ssh-copy-id script. The default settings don't > allow this command to work normally and causes login failures. > > A reasonable workaround could be adding some threshold for a number of > failures before the penalties are applied. That's how the penalty system works now. Can you provide an example session that is failing? The default threshold is three authentication failures in a fifteen second period. I guess you have more keys than that? IMO it's probably ssh-copy-id that needs to change. It looks like it filters public keys by trying them against a target host. IMO it should check them directly against authorized_keys on the target system, as that wouldn't cause login failures and will result in less logspam for server operators. -d From phil at hands.com Tue Dec 10 19:12:36 2024 From: phil at hands.com (Philip Hands) Date: Tue, 10 Dec 2024 09:12:36 +0100 Subject: PerSourcePenalties and ssh-copy-id In-Reply-To: References: Message-ID: <8734iw2byj.fsf@hands.com> Damien Miller writes: > On Mon, 9 Dec 2024, Dmitry Belyavskiy wrote: > >> Dear colleagues, >> >> Can we somehow improve the UX related to a relatively freshly >> introduced PerSourcePenalties option? >> >> A popular pattern implies installation of the users' keys to a freshly >> installed machine using ssh-copy-id script. The default settings don't >> allow this command to work normally and causes login failures. >> >> A reasonable workaround could be adding some threshold for a number of >> failures before the penalties are applied. > > That's how the penalty system works now. > > Can you provide an example session that is failing? The default threshold > is three authentication failures in a fifteen second period. I guess you > have more keys than that? I just bumped into this for ssh-copy-id's CI tests, which broke because the tests launch loads of intentionally failing login attempts, and then try a few that are supposed to work (so I'm now disabling PerSourcePenalties for the test server). > IMO it's probably ssh-copy-id that needs to change. It looks like it > filters public keys by trying them against a target host. That is indeed how it currently works. > IMO it should check them directly against authorized_keys on the > target system, It's not clear to me how that can be reliably achieved. People quite often add keys via other means, like getting them from LDAP, or having a system-wide config in addition to the keys in authorized_keys, and that's for things where the other end is openssh. ssh-copy-id is also supposed to work for things that are not running openssh, like dropbear, so I'm not sure what assumptions I can safely make about what the other end is doing to handle keys. > as that wouldn't cause login failures and will result in less logspam > for server operators. What I could do is notice when people have too many keys, and warn about the possibility that they'll get locked out. I may well be doing multiple redundant attempts with the same key (I'll have to check on that) in which case I could try harder to only test any key once. I guess for people that have many keys to test, I could take note of how many failures I get, and could then introduce a delay between the tests to avoid triggering the default settings. Can one reset the penalty system's count by having a successful login? If so I could make a point of logging-in with a working key in between the key tests (or initiating a password-based login if we don't yet have a working key, although that seems likely to be a pain for the user -- getting at least one key installed early seems like the way to go) Cheers, Phil. -- Philip Hands -- https://hands.com/~phil -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From djm at mindrot.org Thu Dec 12 08:22:08 2024 From: djm at mindrot.org (Damien Miller) Date: Thu, 12 Dec 2024 08:22:08 +1100 (AEDT) Subject: PerSourcePenalties and ssh-copy-id In-Reply-To: <8734iw2byj.fsf@hands.com> References: <8734iw2byj.fsf@hands.com> Message-ID: <92882482-c589-fb5f-d904-33449e3cf51c@mindrot.org> On Tue, 10 Dec 2024, Philip Hands wrote: > > IMO it's probably ssh-copy-id that needs to change. It looks like it > > filters public keys by trying them against a target host. > > That is indeed how it currently works. > > > IMO it should check them directly against authorized_keys on the > > target system, > > It's not clear to me how that can be reliably achieved. People quite > often add keys via other means, like getting them from LDAP, or having a > system-wide config in addition to the keys in authorized_keys, and > that's for things where the other end is openssh. How about this: if authorized_keys exists, then check it, otherwise fall back to trying each key sequentially. -d From msekleta at redhat.com Tue Dec 17 00:51:31 2024 From: msekleta at redhat.com (Michal Sekletar) Date: Mon, 16 Dec 2024 14:51:31 +0100 Subject: PAM session setup and environment variables Message-ID: Hello everyone, I am trying to adjust the systemd-logind classification of the SSH session opened by Ansible client. By default the SSH session created by Ansible client is Class=user and Type=tty in systemd-logind. pam_systemd.so allows users to change this default via the environment variables XDG_SESSION_CLASS and XDG_SESSION_TYPE. When I set these variables on the client and make sure they are accepted by the server I observe in the log that variables are set but that happens *after* PAM session is created in the child process. Hence I have two obvious questions... Is my analysis correct and thus it is not possible to influence PAM session set up via environment variables set by the client? If so, would you be open to accepting the patch to change that, i.e. all environment variables set by the client would be exposed in the child process that opens the PAM session? Cheers, Michal PS: I want to be able to distinguish between "normal" ssh sessions and Ansible sessions as I think that Ansible sessions have slightly different semantics, e.g. no idle timeouts should apply to them even if they allocate PTY, similar to cron sessions. From ab at samba.org Tue Dec 17 01:19:20 2024 From: ab at samba.org (Alexander Bokovoy) Date: Mon, 16 Dec 2024 16:19:20 +0200 Subject: PAM session setup and environment variables In-Reply-To: References: Message-ID: On ???, 16 ??? 2024, Michal Sekletar wrote: > Hello everyone, > > I am trying to adjust the systemd-logind classification of the SSH > session opened by Ansible client. By default the SSH session created > by Ansible client is Class=user and Type=tty in systemd-logind. > pam_systemd.so allows users to change this default via the environment > variables XDG_SESSION_CLASS and XDG_SESSION_TYPE. When I set these > variables on the client and make sure they are accepted by the server > I observe in the log that variables are set but that happens *after* > PAM session is created in the child process. Hence I have two obvious > questions... > > Is my analysis correct and thus it is not possible to influence PAM > session set up via environment variables set by the client? If so, > would you be open to accepting the patch to change that, i.e. all > environment variables set by the client would be exposed in the child > process that opens the PAM session? pam_systemd enforces class 'user' for anything coming from SSH in pam_sm_open_session. Here is a relevant fragment: ------------------------------------------------------- } else if (streq_ptr(tty, "cron")) { /* cron is setting PAM_TTY to "cron" for some reason (the commit carries no information why, but * probably because it wants to set it to something as pam_time/pam_access/? require PAM_TTY to be set * (as they otherwise even try to update it!) ? but cron doesn't actually allocate a TTY for its forked * off processes.) */ type = "unspecified"; class = "background"; tty = NULL; } else if (streq_ptr(tty, "ssh")) { /* ssh has been setting PAM_TTY to "ssh" (for the same reason as cron does this, see above. For further * details look for "PAM_TTY_KLUDGE" in the openssh sources). */ type = "tty"; class = "user"; tty = NULL; /* This one is particularly sad, as this means that ssh sessions ? even though usually * associated with a pty ? won't be tracked by their tty in logind. This is because ssh * does the PAM session registration early for new connections, and registers a pty only * much later (this is because it doesn't know yet if it needs one at all, as whether to * register a pty or not is negotiated much later in the protocol). */ ------------------------------------------------------- This is in reaction to OpenSSH enforcing PAM_TTY_KLUDGE set to 1 unconditionally when being build on Linux. This override in pam_systemd happens after it derived a type, class, and the rest of possible settings from the configuration and PAM environment, so it will not really help to just pass-through the environment variables. > > Cheers, > Michal > > PS: I want to be able to distinguish between "normal" ssh sessions and > Ansible sessions as I think that Ansible sessions have slightly > different semantics, e.g. no idle timeouts should apply to them even > if they allocate PTY, similar to cron sessions. > > _______________________________________________ > openssh-unix-dev mailing list > openssh-unix-dev at mindrot.org > https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev -- / Alexander Bokovoy From msekleta at redhat.com Tue Dec 17 03:50:47 2024 From: msekleta at redhat.com (Michal Sekletar) Date: Mon, 16 Dec 2024 17:50:47 +0100 Subject: PAM session setup and environment variables In-Reply-To: References: Message-ID: On Mon, Dec 16, 2024 at 3:22?PM Alexander Bokovoy via openssh-unix-dev wrote: > This override in pam_systemd happens after it derived a type, class, and > the rest of possible settings from the configuration and PAM > environment, so it will not really help to just pass-through the > environment variables. You are right, however, I have a local version where I've changed this particular piece of code to respect environment variables even for case of SSH. I wanted to submit it upstream, but I've noticed that I am unable to pass in environment variables in the first place. Michal From djm at mindrot.org Tue Dec 17 15:37:44 2024 From: djm at mindrot.org (Damien Miller) Date: Tue, 17 Dec 2024 15:37:44 +1100 (AEDT) Subject: PAM session setup and environment variables In-Reply-To: References: Message-ID: On Mon, 16 Dec 2024, Michal Sekletar wrote: > Hello everyone, > > I am trying to adjust the systemd-logind classification of the SSH > session opened by Ansible client. By default the SSH session created > by Ansible client is Class=user and Type=tty in systemd-logind. > pam_systemd.so allows users to change this default via the environment > variables XDG_SESSION_CLASS and XDG_SESSION_TYPE. When I set these > variables on the client and make sure they are accepted by the server > I observe in the log that variables are set but that happens *after* > PAM session is created in the child process. Hence I have two obvious > questions... > > Is my analysis correct and thus it is not possible to influence PAM > session set up via environment variables set by the client? If so, > would you be open to accepting the patch to change that, i.e. all > environment variables set by the client would be exposed in the child > process that opens the PAM session? User-specified environment variables are not propogated to the environment where sshd invokes PAM modules because the SSH protocol sends them at the time a session is opened, well after authentication has completed. At best, they could be made available to the PAM session modules but there's no way to make user-specified environment available to auth and account modules. Similarly, environment variables _set by_ PAM override anything the user set by SetEnv/SendEnv, on the basis that admin-specified environment shouldn't be manipuable by a (usually) unprivileged user. -d From msekleta at redhat.com Wed Dec 18 02:16:43 2024 From: msekleta at redhat.com (Michal Sekletar) Date: Tue, 17 Dec 2024 16:16:43 +0100 Subject: PAM session setup and environment variables In-Reply-To: References: Message-ID: On Tue, Dec 17, 2024 at 5:40?AM Damien Miller wrote: > User-specified environment variables are not propogated to the > environment where sshd invokes PAM modules because the SSH protocol > sends them at the time a session is opened, well after authentication > has completed. At best, they could be made available to the PAM > session modules but there's no way to make user-specified environment > available to auth and account modules. I am interested in pam_systemd.so which is a session module. Hence, would you accept a patch that exposes these variables during this phase of a session setup? > Similarly, environment variables _set by_ PAM override anything the > user set by SetEnv/SendEnv, on the basis that admin-specified > environment shouldn't be manipuable by a (usually) unprivileged > user. I think this makes sense and shouldn't be changed. Michal > > -d > From djm at mindrot.org Wed Dec 18 15:00:04 2024 From: djm at mindrot.org (Damien Miller) Date: Wed, 18 Dec 2024 15:00:04 +1100 (AEDT) Subject: PAM session setup and environment variables In-Reply-To: References: Message-ID: <6a12afac-e079-9417-9f3d-1466efc795f4@mindrot.org> On Tue, 17 Dec 2024, Michal Sekletar wrote: > On Tue, Dec 17, 2024 at 5:40?AM Damien Miller wrote: > > > User-specified environment variables are not propogated to the > > environment where sshd invokes PAM modules because the SSH protocol > > sends them at the time a session is opened, well after authentication > > has completed. At best, they could be made available to the PAM > > session modules but there's no way to make user-specified environment > > available to auth and account modules. > > I am interested in pam_systemd.so which is a session module. Hence, > would you accept a patch that exposes these variables during this > phase of a session setup? We could potentially allow-list some variables, but I'd like to get some input from people who (for example) maintain PAM for distributions on what is acceptable. -d From djm at mindrot.org Fri Dec 20 09:25:11 2024 From: djm at mindrot.org (Damien Miller) Date: Fri, 20 Dec 2024 09:25:11 +1100 (AEDT) Subject: PAM session setup and environment variables In-Reply-To: <20241219173102.GA13630@strace.io> References: <6a12afac-e079-9417-9f3d-1466efc795f4@mindrot.org> <20241219173102.GA13630@strace.io> Message-ID: On Thu, 19 Dec 2024, Dmitry V. Levin wrote: > > We could potentially allow-list some variables, but I'd like to get > > some input from people who (for example) maintain PAM for distributions > > on what is acceptable. > > With my Linux-PAM hat on, the most essential difference between the > authenticated user code that currently gets the environment variables > listed in AcceptEnv, and the PAM modules session code that currently > doesn't get them, is that PAM modules session code is privileged, so extra > care should be taken not to forward there accidentally any environment > variables that could affect that privileged code in an unintended way. > > While XDG_SESSION_CLASS and XDG_SESSION_TYPE variables mentioned by Michal > are harmless, those LC_* variables AcceptEnv'ed in many default setups are > also likely to be OK, allowing arbitrary variables listed in AcceptEnv > could be risky given that some PAM session modules like pam_namespace and > pam_exec invoke external executables and could be affected by e.g. LD_* > variables. > > If we're aiming for flexibility without sacrificing security, then a new > sshd_config keyword (e.g. PAMSessionAcceptEnv) could be added to specify > what is allowed to be forwarded to the PAM session modules. Thanks for chiming in. How about we accept variables from a narrow allow- list (XDG_SESSION_CLASS/TYPE, LC_*) for now and see how it goes? -d From ldv at strace.io Fri Dec 20 21:07:03 2024 From: ldv at strace.io (Dmitry V. Levin) Date: Fri, 20 Dec 2024 12:07:03 +0200 Subject: PAM session setup and environment variables In-Reply-To: References: <6a12afac-e079-9417-9f3d-1466efc795f4@mindrot.org> <20241219173102.GA13630@strace.io> Message-ID: <20241220100703.GA25647@strace.io> On Fri, Dec 20, 2024 at 09:25:11AM +1100, Damien Miller wrote: > On Thu, 19 Dec 2024, Dmitry V. Levin wrote: > > > > We could potentially allow-list some variables, but I'd like to get > > > some input from people who (for example) maintain PAM for distributions > > > on what is acceptable. > > > > With my Linux-PAM hat on, the most essential difference between the > > authenticated user code that currently gets the environment variables > > listed in AcceptEnv, and the PAM modules session code that currently > > doesn't get them, is that PAM modules session code is privileged, so extra > > care should be taken not to forward there accidentally any environment > > variables that could affect that privileged code in an unintended way. > > > > While XDG_SESSION_CLASS and XDG_SESSION_TYPE variables mentioned by Michal > > are harmless, those LC_* variables AcceptEnv'ed in many default setups are > > also likely to be OK, allowing arbitrary variables listed in AcceptEnv > > could be risky given that some PAM session modules like pam_namespace and > > pam_exec invoke external executables and could be affected by e.g. LD_* > > variables. > > > > If we're aiming for flexibility without sacrificing security, then a new > > sshd_config keyword (e.g. PAMSessionAcceptEnv) could be added to specify > > what is allowed to be forwarded to the PAM session modules. > > Thanks for chiming in. How about we accept variables from a narrow allow- > list (XDG_SESSION_CLASS/TYPE, LC_*) for now and see how it goes? Sounds good. Since nobody asked to forward LC_* and LANG variables to the PAM session modules yet, we could start with just XDG_SESSION_CLASS and XDG_SESSION_TYPE variables. -- ldv From philipp at marek.priv.at Fri Dec 20 21:42:31 2024 From: philipp at marek.priv.at (Philipp Marek) Date: Fri, 20 Dec 2024 11:42:31 +0100 Subject: PAM session setup and environment variables In-Reply-To: <20241220100703.GA25647@strace.io> References: <6a12afac-e079-9417-9f3d-1466efc795f4@mindrot.org> <20241219173102.GA13630@strace.io> <20241220100703.GA25647@strace.io> Message-ID: <6e70c2192b4735d5cba8d9b6b7e306fd@marek.priv.at> >> > If we're aiming for flexibility without sacrificing security, then a new >> > sshd_config keyword (e.g. PAMSessionAcceptEnv) could be added to specify >> > what is allowed to be forwarded to the PAM session modules. >> >> Thanks for chiming in. How about we accept variables from a narrow >> allow- >> list (XDG_SESSION_CLASS/TYPE, LC_*) for now and see how it goes? > > Sounds good. Since nobody asked to forward LC_* and LANG variables to > the > PAM session modules yet, we could start with just XDG_SESSION_CLASS and > XDG_SESSION_TYPE variables. Wouldn't it be better (as in, more secure) to define the session type and/or class on the server side in the authorized_keys line? That would provide the "if our monitoring system comes asking" differentiation without allowing any new untrusted client-side data. Or is that too late already? Thinking more about this, a Match in sshd_config might also be helpful -- though that can't (as of yet) use the incoming pubkey. But at least the logical incoming user can be matched up, even if that one then translates to "just" another UID 0 or whatever. From me at lstlx.com Sun Dec 22 05:15:30 2024 From: me at lstlx.com (Xavier Hsinyuan) Date: Sun, 22 Dec 2024 02:15:30 +0800 Subject: [PATCH 0/2] Fix Memory Management Issue in `ssh-sk-helper` with External SK Libraries Message-ID: <20241221181532.69665-1-me@lstlx.com> Hi, Sometimes, users might find that the `ssh-sk-helper` crashes after enrolling a new key when using external SK libraries. Currently, the memory returned by SK APIs is freed by the host, but external libraries may have their own methods of handling memory. For instance some external libraries are linked against a foreign libc statically. As a result, the `ssh-sk-helper` would have issues if it tries to free memory allocated by external libraries. To resolve this problem, here are two patches: 1 - A patch introduces new APIs to free memory allocated by external libraries, helping to prevent unexpected memory-related behavior when using external SK libraries. 2 - A patch adopts new APIs for bundled `sk-usbhid` and `sk-dummy`. Thank you for your time and feedback. Best regards, Xavier Hsinyuan ------ Xavier Hsinyuan (2): Introduce new SK APIs for freeing memory Adopt new SecurityKey API for sk-usbhid and sk-dummy regress/misc/sk-dummy/sk-dummy.c | 35 +++++++++++++- sk-api.h | 11 ++++- sk-usbhid.c | 55 +++++++++++++++++++++ ssh-sk.c | 83 ++++++++++++++------------------ 4 files changed, 136 insertions(+), 48 deletions(-) -- 2.39.5 From me at lstlx.com Sun Dec 22 05:15:31 2024 From: me at lstlx.com (Xavier Hsinyuan) Date: Sun, 22 Dec 2024 02:15:31 +0800 Subject: [PATCH 1/2] Introduce new SK APIs for freeing memory In-Reply-To: <20241221181532.69665-1-me@lstlx.com> References: <20241221181532.69665-1-me@lstlx.com> Message-ID: <20241221181532.69665-2-me@lstlx.com> External SecurityKey middleware libraries may use different memory allocation methods for SK API responses. `ssh-sk-helper` may exhibit unexpected behavior if it frees memory allocated by external SK libraries. Fixed by introducing new SK APIs for freeing memory allocated by and returned from external SK libraries. --- sk-api.h | 11 ++++++++++- ssh-sk.c | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/sk-api.h b/sk-api.h index 08f567a9e..b61f7235c 100644 --- a/sk-api.h +++ b/sk-api.h @@ -79,7 +79,7 @@ struct sk_option { uint8_t required; }; -#define SSH_SK_VERSION_MAJOR 0x000a0000 /* current API version */ +#define SSH_SK_VERSION_MAJOR 0x000b0000 /* current API version */ #define SSH_SK_VERSION_MAJOR_MASK 0xffff0000 /* Return the version of the middleware API */ @@ -100,4 +100,13 @@ int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len, int sk_load_resident_keys(const char *pin, struct sk_option **options, struct sk_resident_key ***rks, size_t *nrks); +/* Free sk_sign_response allocated by provider */ +void sk_free_enroll_response(struct sk_enroll_response *enroll_resp); + +/* Free sk_sign_response allocated by provider */ +void sk_free_sign_response(struct sk_sign_response *sign_resp); + +/* Free sk_resident_key allocated by provider */ +void sk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks); + #endif /* _SK_API_H */ diff --git a/ssh-sk.c b/ssh-sk.c index a2a7d7206..19ac9dda8 100644 --- a/ssh-sk.c +++ b/ssh-sk.c @@ -78,6 +78,15 @@ struct sshsk_provider { /* Enumerate resident keys */ int (*sk_load_resident_keys)(const char *pin, struct sk_option **opts, struct sk_resident_key ***rks, size_t *nrks); + + /* Free sk_sign_response allocated by provider */ + void (*sk_free_enroll_response)(struct sk_enroll_response *ptr); + + /* Free sk_sign_response allocated by provider */ + void (*sk_free_sign_response)(struct sk_sign_response *ptr); + + /* Free sk_resident_key allocated by provider */ + void (*sk_free_sk_resident_keys)(struct sk_resident_key **rks, size_t nrks); }; /* Built-in version */ @@ -171,6 +180,25 @@ sshsk_open(const char *path) "failed: %s", path, dlerror()); goto fail; } + + if ((ret->sk_free_enroll_response = dlsym(ret->dlhandle, + "sk_free_enroll_response")) == NULL) { + error("Provider \"%s\" dlsym(sk_free_enroll_response) " + "failed: %s", path, dlerror()); + goto fail; + } + if ((ret->sk_free_sign_response = dlsym(ret->dlhandle, + "sk_free_sign_response")) == NULL) { + error("Provider \"%s\" dlsym(sk_free_sign_response) " + "failed: %s", path, dlerror()); + goto fail; + } + if ((ret->sk_free_sk_resident_keys = dlsym(ret->dlhandle, + "sk_free_sk_resident_keys")) == NULL) { + error("Provider \"%s\" dlsym(sk_free_sk_resident_keys) " + "failed: %s", path, dlerror()); + goto fail; + } /* success */ return ret; fail: @@ -568,9 +596,9 @@ sshsk_enroll(int type, const char *provider_path, const char *device, r = 0; out: sshsk_free_options(opts); + skp->sk_free_enroll_response(resp); sshsk_free(skp); sshkey_free(key); - sshsk_free_enroll_response(resp); explicit_bzero(randchall, sizeof(randchall)); return r; } @@ -746,8 +774,8 @@ sshsk_sign(const char *provider_path, struct sshkey *key, r = 0; out: sshsk_free_options(opts); + skp->sk_free_sign_response(resp); sshsk_free(skp); - sshsk_free_sign_response(resp); sshbuf_free(sig); sshbuf_free(inner_sig); return r; @@ -883,8 +911,8 @@ sshsk_load_resident(const char *provider_path, const char *device, r = 0; out: sshsk_free_options(opts); + skp->sk_free_sk_resident_keys(rks, nrks); sshsk_free(skp); - sshsk_free_sk_resident_keys(rks, nrks); sshkey_free(key); sshsk_free_resident_key(srk); sshsk_free_resident_keys(srks, nsrks); -- 2.39.5 From me at lstlx.com Sun Dec 22 05:15:32 2024 From: me at lstlx.com (Xavier Hsinyuan) Date: Sun, 22 Dec 2024 02:15:32 +0800 Subject: [PATCH 2/2] Adopt new SecurityKey API for sk-usbhid and sk-dummy In-Reply-To: <20241221181532.69665-1-me@lstlx.com> References: <20241221181532.69665-1-me@lstlx.com> Message-ID: <20241221181532.69665-3-me@lstlx.com> --- regress/misc/sk-dummy/sk-dummy.c | 35 +++++++++++++++++++- sk-usbhid.c | 55 ++++++++++++++++++++++++++++++++ ssh-sk.c | 49 ++++------------------------ 3 files changed, 95 insertions(+), 44 deletions(-) diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c index 347b21227..de96e7ef5 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c @@ -50,7 +50,7 @@ /* #define SK_DEBUG 1 */ -#if SSH_SK_VERSION_MAJOR != 0x000a0000 +#if SSH_SK_VERSION_MAJOR != 0x000b0000 # error SK API has changed, sk-dummy.c needs an update #endif @@ -59,6 +59,9 @@ # define sk_enroll ssh_sk_enroll # define sk_sign ssh_sk_sign # define sk_load_resident_keys ssh_sk_load_resident_keys +# define sk_free_enroll_response ssh_sk_free_enroll_response +# define sk_free_sign_response ssh_sk_free_sign_response +# define sk_free_resident_keys ssh_sk_free_resident_keys #endif /* !SK_STANDALONE */ static void skdebug(const char *func, const char *fmt, ...) @@ -541,3 +544,33 @@ sk_load_resident_keys(const char *pin, struct sk_option **options, { return SSH_SK_ERR_UNSUPPORTED; } + +void +sk_free_enroll_response(struct sk_enroll_response *enroll_resp) +{ + if (enroll_resp == NULL) + return; + freezero(enroll_resp->key_handle, enroll_resp->key_handle_len); + freezero(enroll_resp->public_key, enroll_resp->public_key_len); + freezero(enroll_resp->signature, enroll_resp->signature_len); + freezero(enroll_resp->attestation_cert, enroll_resp->attestation_cert_len); + freezero(enroll_resp->authdata, enroll_resp->authdata_len); + freezero(enroll_resp, sizeof(*enroll_resp)); +} + +void +sk_free_sign_response(struct sk_sign_response *sign_resp) +{ + if (sign_resp == NULL) + return; + freezero(sign_resp->sig_r, sign_resp->sig_r_len); + freezero(sign_resp->sig_s, sign_resp->sig_s_len); + freezero(sign_resp, sizeof(*sign_resp)); +} + +/* sk_load_resident_keys returns SSH_SK_ERR_UNSUPPORTED */ +void +sk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks) +{ + return; +} diff --git a/sk-usbhid.c b/sk-usbhid.c index 427431b9a..01c68c842 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -90,6 +90,9 @@ # define sk_enroll ssh_sk_enroll # define sk_sign ssh_sk_sign # define sk_load_resident_keys ssh_sk_load_resident_keys +# define sk_free_enroll_response ssh_sk_free_enroll_response +# define sk_free_sign_response ssh_sk_free_sign_response +# define sk_free_sk_resident_keys ssh_sk_free_sk_resident_keys #endif /* !SK_STANDALONE */ #include "sk-api.h" @@ -134,6 +137,15 @@ int sk_sign(uint32_t alg, const uint8_t *data, size_t data_len, int sk_load_resident_keys(const char *pin, struct sk_option **options, struct sk_resident_key ***rks, size_t *nrks); +/* Free sk_sign_response allocated by provider */ +void sk_free_enroll_response(struct sk_enroll_response *enroll_resp); + +/* Free sk_sign_response allocated by provider */ +void sk_free_sign_response(struct sk_sign_response *sign_resp); + +/* Free sk_resident_key allocated by provider */ +void sk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks); + static void skdebug(const char *func, const char *fmt, ...) __attribute__((__format__ (printf, 2, 3))); @@ -1479,4 +1491,47 @@ sk_load_resident_keys(const char *pin, struct sk_option **options, return ret; } +void +sk_free_enroll_response(struct sk_enroll_response *enroll_resp) +{ + if (enroll_resp == NULL) + return; + freezero(enroll_resp->key_handle, enroll_resp->key_handle_len); + freezero(enroll_resp->public_key, enroll_resp->public_key_len); + freezero(enroll_resp->signature, enroll_resp->signature_len); + freezero(enroll_resp->attestation_cert, enroll_resp->attestation_cert_len); + freezero(enroll_resp->authdata, enroll_resp->authdata_len); + freezero(enroll_resp, sizeof(*enroll_resp)); +} + +void +sk_free_sign_response(struct sk_sign_response *sign_resp) +{ + if (sign_resp == NULL) + return; + freezero(sign_resp->sig_r, sign_resp->sig_r_len); + freezero(sign_resp->sig_s, sign_resp->sig_s_len); + freezero(sign_resp, sizeof(*sign_resp)); +} + +void +sk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks) +{ + size_t i; + + if (nrks == 0 || rks == NULL) + return; + for (i = 0; i < nrks; i++) { + free(rks[i]->application); + freezero(rks[i]->user_id, rks[i]->user_id_len); + freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len); + freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); + freezero(rks[i]->key.signature, rks[i]->key.signature_len); + freezero(rks[i]->key.attestation_cert, + rks[i]->key.attestation_cert_len); + freezero(rks[i], sizeof(**rks)); + } + free(rks); +} + #endif /* ENABLE_SK_INTERNAL */ diff --git a/ssh-sk.c b/ssh-sk.c index 19ac9dda8..9cc5bd4c1 100644 --- a/ssh-sk.c +++ b/ssh-sk.c @@ -101,6 +101,9 @@ int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len, struct sk_sign_response **sign_response); int ssh_sk_load_resident_keys(const char *pin, struct sk_option **opts, struct sk_resident_key ***rks, size_t *nrks); +void ssh_sk_free_enroll_response(struct sk_enroll_response *enroll_resp); +void ssh_sk_free_sign_response(struct sk_sign_response *enroll_resp); +void ssh_sk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks); static void sshsk_free(struct sshsk_provider *p) @@ -137,6 +140,9 @@ sshsk_open(const char *path) ret->sk_enroll = ssh_sk_enroll; ret->sk_sign = ssh_sk_sign; ret->sk_load_resident_keys = ssh_sk_load_resident_keys; + ret->sk_free_enroll_response = ssh_sk_free_enroll_response; + ret->sk_free_sign_response = ssh_sk_free_sign_response; + ret->sk_free_sk_resident_keys = ssh_sk_free_sk_resident_keys; return ret; #else error("internal security key support not enabled"); @@ -206,29 +212,6 @@ fail: return NULL; } -static void -sshsk_free_enroll_response(struct sk_enroll_response *r) -{ - if (r == NULL) - return; - freezero(r->key_handle, r->key_handle_len); - freezero(r->public_key, r->public_key_len); - freezero(r->signature, r->signature_len); - freezero(r->attestation_cert, r->attestation_cert_len); - freezero(r->authdata, r->authdata_len); - freezero(r, sizeof(*r)); -} - -static void -sshsk_free_sign_response(struct sk_sign_response *r) -{ - if (r == NULL) - return; - freezero(r->sig_r, r->sig_r_len); - freezero(r->sig_s, r->sig_s_len); - freezero(r, sizeof(*r)); -} - #ifdef WITH_OPENSSL /* Assemble key from response */ static int @@ -781,26 +764,6 @@ sshsk_sign(const char *provider_path, struct sshkey *key, return r; } -static void -sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks) -{ - size_t i; - - if (nrks == 0 || rks == NULL) - return; - for (i = 0; i < nrks; i++) { - free(rks[i]->application); - freezero(rks[i]->user_id, rks[i]->user_id_len); - freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len); - freezero(rks[i]->key.public_key, rks[i]->key.public_key_len); - freezero(rks[i]->key.signature, rks[i]->key.signature_len); - freezero(rks[i]->key.attestation_cert, - rks[i]->key.attestation_cert_len); - freezero(rks[i], sizeof(**rks)); - } - free(rks); -} - static void sshsk_free_resident_key(struct sshsk_resident_key *srk) { -- 2.39.5 From simon at josefsson.org Mon Dec 23 12:06:35 2024 From: simon at josefsson.org (Simon Josefsson) Date: Mon, 23 Dec 2024 02:06:35 +0100 Subject: SPHINCS+ support for OpenSSH Message-ID: <875xnbtdgk.fsf@kaka.sjd.se> Hi I have pushed a (quite preliminary) branch that adds SPHINCS+ SSH signature support for OpenSSH: https://github.com/jas4711/openssh-portable/tree/sphincsp I've written a bit about it here: https://blog.josefsson.org/2024/12/23/openssh-and-git-on-a-post-quantum-sphincs/ What do you think? My primary use-case is for ssh-keygen -Y sign/verify usage to protect Git commits. It isn't inconceivable that someone would find interactive SSH use of interest, although I didn't make an effort to test this. /Simon -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 255 bytes Desc: not available URL: