]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: Help OpenSSH's PKCS#11 support kick its meth habit.
authordjm@openbsd.org <djm@openbsd.org>
Thu, 24 Jul 2025 05:44:55 +0000 (05:44 +0000)
committerDamien Miller <djm@mindrot.org>
Thu, 24 Jul 2025 23:23:16 +0000 (09:23 +1000)
The PKCS#11 code in OpenSSH used the libcrypto public key method API
(e.g. the delightfully named RSA_meth_free()) to delegate signing
operations to external keys. This had one advantage - that it was
basically transparent to callers, but also had a big disadvantage -
that we'd manually have to track the method implementations, their
state and their relationships to the underlying PKCS#11 objects.

This rips this out and replaces it with explicit delegation to
PKCS#11 code for externally hosted keys via the ssh-pkcs11-helper
subprocess. This is very similar to how we handle FIDO keys in
OpenSSH (i.e. via ssh-sk-helper). All we need to track now is a
much simpler mapping of public key -> helper subprocess.

Kicking our libcrypto meth dependency also makes it much easier
to support Ed25519 keys in PKCS#11, which will happen in a subsequent
commit.

feedback / ok tb@

OpenBSD-Commit-ID: a5a1eaf57971cf15e0cdc5a513e313541c8a35f0

13 files changed:
.depend
Makefile.in
ssh-ecdsa.c
ssh-pkcs11-client.c
ssh-pkcs11-helper.c
ssh-pkcs11.c
ssh-pkcs11.h
ssh-rsa.c
ssh-sk-helper.c
sshbuf-misc.c
sshbuf.h
sshkey.c
sshkey.h

diff --git a/.depend b/.depend
index 3e64eb84a6a59acf3bbb8d9e8c51144f4401a593..f569b603d450184d1d24f6a16ff79f9efbbd8424 100644 (file)
--- a/.depend
+++ b/.depend
@@ -138,12 +138,12 @@ ssh-keygen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-co
 ssh-keyscan.o: dispatch.h log.h ssherr.h atomicio.h misc.h hostfile.h ssh_api.h ssh2.h dns.h addr.h
 ssh-keyscan.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshbuf.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h kex.h mac.h crypto_api.h compat.h myproposal.h packet.h
 ssh-keysign.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h ssh.h ssh2.h misc.h sshbuf.h authfile.h msg.h canohost.h pathnames.h readconf.h uidswap.h
-ssh-pkcs11-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h
+ssh-pkcs11-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h pathnames.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h atomicio.h ssh-pkcs11.h
+ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h
 ssh-pkcs11.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshkey.h
 ssh-rsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
 ssh-sk-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshbuf.h sshkey.h msg.h digest.h pathnames.h ssh-sk.h misc.h
-ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h
+ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h ssh-pkcs11.h
 ssh-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
 ssh-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
 ssh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h canohost.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h packet.h dispatch.h sshbuf.h channels.h
@@ -163,11 +163,11 @@ sshd-auth.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h ke
 sshd-auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h
 sshd-session.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h dh.h
 sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h
-sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h
+sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h monitor_wrap.h
 sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshpty.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h digest.h sshkey.h authfile.h pathnames.h canohost.h hostfile.h auth.h auth-pam.h
 ssherr.o: ssherr.h
 sshkey-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h
-sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h openbsd-compat/openssl-compat.h
+sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h ssh-pkcs11.h openbsd-compat/openssl-compat.h
 sshlogin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshlogin.h ssherr.h loginrec.h log.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h
 sshpty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h log.h ssherr.h misc.h
 sshsig.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfd.h authfile.h log.h ssherr.h misc.h sshbuf.h sshsig.h sshkey.h match.h digest.h
index eb6f08e4df9bd08b3d8278d940291bcdf448a09d..399c8ae6ec56f7925e51b24d0fceab65cb5ab3cd 100644 (file)
@@ -108,7 +108,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
        monitor_fdpass.o rijndael.o ssh-ecdsa.o ssh-ecdsa-sk.o \
        ssh-ed25519-sk.o ssh-rsa.o dh.o \
        msg.o dns.o entropy.o gss-genr.o umac.o umac128.o \
-       ssh-pkcs11.o smult_curve25519_ref.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 \
@@ -118,16 +118,18 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
        sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
        sshbuf-io.o misc-agent.o
 
+P11OBJS= ssh-pkcs11-client.o
+
 SKOBJS=        ssh-sk-client.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
-       sshconnect.o sshconnect2.o mux.o $(SKOBJS)
+       sshconnect.o sshconnect2.o mux.o $(P11OBJS) $(SKOBJS)
 
 SSHDOBJS=sshd.o \
        platform-listen.o \
        servconf.o sshpty.o srclimit.o groupaccess.o auth2-methods.o \
        dns.o fatal.o compat.o utf8.o authfd.o canohost.o \
-       $(SKOBJS)
+       $(P11OBJS) $(SKOBJS)
 
 SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \
        audit.o audit-bsm.o audit-linux.o platform.o \
@@ -140,7 +142,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.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 \
-       uidswap.o platform-listen.o $(SKOBJS)
+       uidswap.o platform-listen.o $(P11OBJS) $(SKOBJS)
 
 SSHD_AUTH_OBJS=sshd-auth.o \
        auth2-methods.o \
@@ -155,25 +157,25 @@ SSHD_AUTH_OBJS=sshd-auth.o \
        sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \
        sandbox-seccomp-filter.o sandbox-capsicum.o  sandbox-solaris.o \
        sftp-server.o sftp-common.o \
-       uidswap.o $(SKOBJS)
+       uidswap.o $(P11OBJS) $(SKOBJS)
 
 SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o
 
 SCP_OBJS=      scp.o progressmeter.o $(SFTP_CLIENT_OBJS)
 
-SSHADD_OBJS=   ssh-add.o $(SKOBJS)
+SSHADD_OBJS=   ssh-add.o $(P11OBJS) $(SKOBJS)
 
-SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS)
+SSHAGENT_OBJS= ssh-agent.o $(P11OBJS) $(SKOBJS)
 
-SSHKEYGEN_OBJS=        ssh-keygen.o sshsig.o $(SKOBJS)
+SSHKEYGEN_OBJS=        ssh-keygen.o sshsig.o $(P11OBJS) $(SKOBJS)
 
-SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(SKOBJS)
+SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(P11OBJS) $(SKOBJS)
 
 P11HELPER_OBJS=        ssh-pkcs11-helper.o ssh-pkcs11.o $(SKOBJS)
 
 SKHELPER_OBJS= ssh-sk-helper.o ssh-sk.o sk-usbhid.o
 
-SSHKEYSCAN_OBJS=ssh-keyscan.o $(SKOBJS)
+SSHKEYSCAN_OBJS=ssh-keyscan.o $(P11OBJS) $(SKOBJS)
 
 SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o
 
index 695ed451e63d64a235854e14bb127663e697bee2..b423bfb65685e789feee14a76f63c6e28f241923 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.28 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -328,8 +328,7 @@ ssh_ecdsa_sign(struct sshkey *key,
        const BIGNUM *sig_r, *sig_s;
        int hash_alg;
        size_t slen = 0;
-       struct sshbuf *b = NULL, *bb = NULL;
-       int len = 0, ret = SSH_ERR_INTERNAL_ERROR;
+       int ret = SSH_ERR_INTERNAL_ERROR;
 
        if (lenp != NULL)
                *lenp = 0;
@@ -352,11 +351,37 @@ ssh_ecdsa_sign(struct sshkey *key,
                ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
+       ECDSA_SIG_get0(esig, &sig_r, &sig_s);
+
+       if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s,
+           sigp, lenp)) != 0)
+               goto out;
+       /* success */
+       ret = 0;
+ out:
+       freezero(sigb, slen);
+       ECDSA_SIG_free(esig);
+       return ret;
+}
+
+int
+ssh_ecdsa_encode_store_sig(const struct sshkey *key,
+    const BIGNUM *sig_r, const BIGNUM *sig_s,
+    u_char **sigp, size_t *lenp)
+{
+       struct sshbuf *b = NULL, *bb = NULL;
+       int ret;
+       size_t len;
+
+       if (lenp != NULL)
+               *lenp = 0;
+       if (sigp != NULL)
+               *sigp = NULL;
+
        if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       ECDSA_SIG_get0(esig, &sig_r, &sig_s);
        if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 ||
            (ret = sshbuf_put_bignum2(bb, sig_s)) != 0)
                goto out;
@@ -375,10 +400,8 @@ ssh_ecdsa_sign(struct sshkey *key,
                *lenp = len;
        ret = 0;
  out:
-       freezero(sigb, slen);
        sshbuf_free(b);
        sshbuf_free(bb);
-       ECDSA_SIG_free(esig);
        return ret;
 }
 
index b8d1700f0296dc48ea9227d3ca73dc249174755d..8aaa4d2d684ce75a0829746f7bd85f9ed66b5b7b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11-client.c,v 1.20 2024/08/15 00:51:51 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11-client.c,v 1.21 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -18,8 +18,6 @@
 
 #include "includes.h"
 
-#ifdef ENABLE_PKCS11
-
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #include <sys/socket.h>
 
 #include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <limits.h>
 
-#include <openssl/ecdsa.h>
-#include <openssl/rsa.h>
-
 #include "pathnames.h"
 #include "xmalloc.h"
 #include "sshbuf.h"
 #include "ssh-pkcs11.h"
 #include "ssherr.h"
 
-#include "openbsd-compat/openssl-compat.h"
-
-#if !defined(OPENSSL_HAS_ECC) || !defined(HAVE_EC_KEY_METHOD_NEW)
-#define EC_KEY_METHOD void
-#define EC_KEY void
-#endif
-
 /* borrows code from sftp-server and ssh-agent */
 
 /*
  * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up
- * by provider path or their unique EC/RSA METHOD pointers.
+ * by provider path or their unique keyblobs.
  */
 struct helper {
        char *path;
        pid_t pid;
        int fd;
-       RSA_METHOD *rsa_meth;
-       EC_KEY_METHOD *ec_meth;
-       int (*rsa_finish)(RSA *rsa);
-       void (*ec_finish)(EC_KEY *key);
-       size_t nrsa, nec; /* number of active keys of each type */
+       size_t nkeyblobs;
+       struct sshbuf **keyblobs; /* XXX use a tree or something faster */
 };
 static struct helper **helpers;
 static size_t nhelpers;
@@ -88,58 +74,75 @@ helper_by_provider(const char *path)
 }
 
 static struct helper *
-helper_by_rsa(const RSA *rsa)
+helper_by_key(const struct sshkey *key)
 {
-       size_t i;
-       const RSA_METHOD *meth;
+       size_t i, j;
+       struct sshbuf *keyblob = NULL;
+       int r;
+
+       if ((keyblob = sshbuf_new()) == NULL)
+               fatal_f("sshbuf_new failed");
+       if ((r = sshkey_putb(key, keyblob)) != 0)
+               fatal_fr(r, "serialise key");
 
-       if ((meth = RSA_get_method(rsa)) == NULL)
-               return NULL;
        for (i = 0; i < nhelpers; i++) {
-               if (helpers[i] != NULL && helpers[i]->rsa_meth == meth)
-                       return helpers[i];
+               if (helpers[i] == NULL)
+                       continue;
+               for (j = 0; j < helpers[i]->nkeyblobs; j++) {
+                       if (sshbuf_equals(keyblob,
+                           helpers[i]->keyblobs[j]) == 0) {
+                               sshbuf_free(keyblob);
+                               return helpers[i];
+                       }
+               }
        }
+       sshbuf_free(keyblob);
        return NULL;
 
 }
 
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-static struct helper *
-helper_by_ec(const EC_KEY *ec)
+static void
+helper_add_key(struct helper *helper, struct sshkey *key)
 {
-       size_t i;
-       const EC_KEY_METHOD *meth;
-
-       if ((meth = EC_KEY_get_method(ec)) == NULL)
-               return NULL;
-       for (i = 0; i < nhelpers; i++) {
-               if (helpers[i] != NULL && helpers[i]->ec_meth == meth)
-                       return helpers[i];
-       }
-       return NULL;
+       int r;
 
+       helper->keyblobs = xrecallocarray(helper->keyblobs, helper->nkeyblobs,
+           helper->nkeyblobs + 1, sizeof(*helper->keyblobs));
+       if ((helper->keyblobs[helper->nkeyblobs] = sshbuf_new()) == NULL)
+               fatal_f("sshbuf_new failed");
+       if ((r = sshkey_putb(key, helper->keyblobs[helper->nkeyblobs])) != 0)
+               fatal_fr(r, "shkey_putb failed");
+       helper->nkeyblobs++;
+       debug3_f("added %s key for provider %s, now has %zu keys",
+           sshkey_type(key), helper->path, helper->nkeyblobs);
 }
-#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */
 
 static void
-helper_free(struct helper *helper)
+helper_terminate(struct helper *helper)
 {
        size_t i;
        int found = 0;
 
        if (helper == NULL)
                return;
-       if (helper->path == NULL || helper->ec_meth == NULL ||
-           helper->rsa_meth == NULL)
+       if (helper->path == NULL)
                fatal_f("inconsistent helper");
-       debug3_f("free helper for provider %s", helper->path);
+
+       debug3_f("terminating helper for %s; remaining %zu keys",
+           helper->path, helper->nkeyblobs);
+
+       close(helper->fd);
+       /* XXX waitpid() */
+       helper->fd = -1;
+       helper->pid = -1;
+
+       /* repack helpers */
        for (i = 0; i < nhelpers; i++) {
                if (helpers[i] == helper) {
                        if (found)
                                fatal_f("helper recorded more than once");
                        found = 1;
-               }
-               else if (found)
+               } else if (found)
                        helpers[i - 1] = helpers[i];
        }
        if (found) {
@@ -147,39 +150,12 @@ helper_free(struct helper *helper)
                    nhelpers - 1, sizeof(*helpers));
                nhelpers--;
        }
+       for (i = 0; i < helper->nkeyblobs; i++)
+               sshbuf_free(helper->keyblobs[i]);
        free(helper->path);
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       EC_KEY_METHOD_free(helper->ec_meth);
-#endif
-       RSA_meth_free(helper->rsa_meth);
        free(helper);
 }
 
-static void
-helper_terminate(struct helper *helper)
-{
-       if (helper == NULL) {
-               return;
-       } else if (helper->fd == -1) {
-               debug3_f("already terminated");
-       } else {
-               debug3_f("terminating helper for %s; "
-                   "remaining %zu RSA %zu ECDSA",
-                   helper->path, helper->nrsa, helper->nec);
-               close(helper->fd);
-               /* XXX waitpid() */
-               helper->fd = -1;
-               helper->pid = -1;
-       }
-       /*
-        * Don't delete the helper entry until there are no remaining keys
-        * that reference it. Otherwise, any signing operation would call
-        * a free'd METHOD pointer and that would be bad.
-        */
-       if (helper->nrsa == 0 && helper->nec == 0)
-               helper_free(helper);
-}
-
 static void
 send_msg(int fd, struct sshbuf *m)
 {
@@ -249,200 +225,61 @@ pkcs11_terminate(void)
                helper_terminate(helpers[i]);
 }
 
-static int
-rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
-       struct sshkey *key = NULL;
        struct sshbuf *msg = NULL;
-       u_char *blob = NULL, *signature = NULL;
-       size_t blen, slen = 0;
-       int r, ret = -1;
        struct helper *helper;
+       int status, r;
+       u_char *signature = NULL;
+       size_t signature_len = 0;
+       int ret = SSH_ERR_INTERNAL_ERROR;
 
-       if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1)
-               fatal_f("no helper for PKCS11 key");
-       debug3_f("signing with PKCS11 provider %s", helper->path);
-       if (padding != RSA_PKCS1_PADDING)
-               goto fail;
-       if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
-               error_f("sshkey_new failed");
-               goto fail;
-       }
-       if ((key->pkey = EVP_PKEY_new()) == NULL ||
-          EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
-               error_f("pkey setup failed");
-               goto fail;
-       }
+       if (sigp != NULL)
+               *sigp = NULL;
+       if (lenp != NULL)
+               *lenp = 0;
+
+       if ((helper = helper_by_key(key)) == NULL || helper->fd == -1)
+               fatal_f("no helper for %s key", sshkey_type(key));
 
-       key->type = KEY_RSA;
-       if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
-               error_fr(r, "encode key");
-               goto fail;
-       }
        if ((msg = sshbuf_new()) == NULL)
-               fatal_f("sshbuf_new failed");
+               return SSH_ERR_ALLOC_FAIL;
        if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
-           (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
-           (r = sshbuf_put_string(msg, from, flen)) != 0 ||
-           (r = sshbuf_put_u32(msg, 0)) != 0)
+           (r = sshkey_puts_plain(key, msg)) != 0 ||
+           (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
+           (r = sshbuf_put_cstring(msg, alg == NULL ? "" : alg)) != 0 ||
+           (r = sshbuf_put_u32(msg, compat)) != 0)
                fatal_fr(r, "compose");
        send_msg(helper->fd, msg);
        sshbuf_reset(msg);
 
-       if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
-               if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
-                       fatal_fr(r, "parse");
-               if (slen <= (size_t)RSA_size(rsa)) {
-                       memcpy(to, signature, slen);
-                       ret = slen;
-               }
-               free(signature);
-       }
- fail:
-       free(blob);
-       sshkey_free(key);
-       sshbuf_free(msg);
-       return (ret);
-}
-
-static int
-rsa_finish(RSA *rsa)
-{
-       struct helper *helper;
-
-       if ((helper = helper_by_rsa(rsa)) == NULL)
-               fatal_f("no helper for PKCS11 key");
-       debug3_f("free PKCS11 RSA key for provider %s", helper->path);
-       if (helper->rsa_finish != NULL)
-               helper->rsa_finish(rsa);
-       if (helper->nrsa == 0)
-               fatal_f("RSA refcount error");
-       helper->nrsa--;
-       debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-           helper->path, helper->nrsa, helper->nec);
-       if (helper->nrsa == 0 && helper->nec == 0)
-               helper_terminate(helper);
-       return 1;
-}
-
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-static ECDSA_SIG *
-ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
-    const BIGNUM *rp, EC_KEY *ec)
-{
-       struct sshkey *key = NULL;
-       struct sshbuf *msg = NULL;
-       ECDSA_SIG *ret = NULL;
-       const u_char *cp;
-       u_char *blob = NULL, *signature = NULL;
-       size_t blen, slen = 0;
-       int r, nid;
-       struct helper *helper;
-
-       if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1)
-               fatal_f("no helper for PKCS11 key");
-       debug3_f("signing with PKCS11 provider %s", helper->path);
-
-       if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
-               error_f("sshkey_new failed");
-               goto fail;
-       }
-       if ((key->pkey = EVP_PKEY_new()) == NULL ||
-           EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) {
-               error("pkey setup failed");
-               goto fail;
-       }
-       if ((nid = sshkey_ecdsa_pkey_to_nid(key->pkey)) < 0) {
-               error("couldn't get curve nid");
+       if ((status = recv_msg(helper->fd, msg)) != SSH2_AGENT_SIGN_RESPONSE) {
+               /* XXX translate status to something useful */
+               debug_fr(r, "recv_msg");
+               ret = SSH_ERR_AGENT_FAILURE;
                goto fail;
        }
-       key->ecdsa_nid = nid;
-       key->type = KEY_ECDSA;
 
-       if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
-               error_fr(r, "encode key");
-               goto fail;
-       }
-       if ((msg = sshbuf_new()) == NULL)
-               fatal_f("sshbuf_new failed");
-       if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
-           (r = sshbuf_put_string(msg, blob, blen)) != 0 ||
-           (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 ||
-           (r = sshbuf_put_u32(msg, 0)) != 0)
-               fatal_fr(r, "compose");
-       send_msg(helper->fd, msg);
-       sshbuf_reset(msg);
+       if ((r = sshbuf_get_string(msg, &signature, &signature_len)) != 0)
+               fatal_fr(r, "parse");
 
-       if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) {
-               if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0)
-                       fatal_fr(r, "parse");
-               cp = signature;
-               ret = d2i_ECDSA_SIG(NULL, &cp, slen);
-               free(signature);
+       /* success */
+       if (sigp != NULL) {
+               *sigp = signature;
+               signature = NULL;
        }
+       if (lenp != NULL)
+               *lenp = signature_len;
+       ret = 0;
 
  fail:
-       free(blob);
-       sshkey_free(key);
        sshbuf_free(msg);
-       return (ret);
-}
-
-static void
-ecdsa_do_finish(EC_KEY *ec)
-{
-       struct helper *helper;
-
-       if ((helper = helper_by_ec(ec)) == NULL)
-               fatal_f("no helper for PKCS11 key");
-       debug3_f("free PKCS11 ECDSA key for provider %s", helper->path);
-       if (helper->ec_finish != NULL)
-               helper->ec_finish(ec);
-       if (helper->nec == 0)
-               fatal_f("ECDSA refcount error");
-       helper->nec--;
-       debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-           helper->path, helper->nrsa, helper->nec);
-       if (helper->nrsa == 0 && helper->nec == 0)
-               helper_terminate(helper);
-}
-#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */
-
-/* redirect private key crypto operations to the ssh-pkcs11-helper */
-static void
-wrap_key(struct helper *helper, struct sshkey *k)
-{
-       RSA *rsa = NULL;
-       EC_KEY *ecdsa = NULL;
-
-       debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path);
-       if (k->type == KEY_RSA) {
-               if ((rsa = EVP_PKEY_get1_RSA(k->pkey)) == NULL)
-                       fatal_f("no RSA key");
-               if (RSA_set_method(rsa, helper->rsa_meth) != 1)
-                       fatal_f("RSA_set_method failed");
-               if (helper->nrsa++ >= INT_MAX)
-                       fatal_f("RSA refcount error");
-               if (EVP_PKEY_set1_RSA(k->pkey, rsa) != 1)
-                       fatal_f("EVP_PKEY_set1_RSA failed");
-               RSA_free(rsa);
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       } else if (k->type == KEY_ECDSA) {
-               if ((ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey)) == NULL)
-                       fatal_f("no ECDSA key");
-               if (EC_KEY_set_method(ecdsa, helper->ec_meth) != 1)
-                       fatal_f("EC_KEY_set_method failed");
-               if (helper->nec++ >= INT_MAX)
-                       fatal_f("EC refcount error");
-               if (EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa) != 1)
-                       fatal_f("EVP_PKEY_set1_EC_KEY failed");
-               EC_KEY_free(ecdsa);
-#endif
-       } else
-               fatal_f("unknown key type");
-       k->flags |= SSHKEY_FLAG_EXT;
-       debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-           helper->path, helper->nrsa, helper->nec);
+       return ret;
 }
 
 /*
@@ -456,13 +293,13 @@ pkcs11_make_cert(const struct sshkey *priv,
        struct helper *helper = NULL;
        struct sshkey *ret;
        int r;
-       RSA *rsa_priv = NULL, *rsa_cert = NULL;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       EC_KEY *ec_priv = NULL, *ec_cert = NULL;
-#endif
 
-       debug3_f("private key type %s cert type %s", sshkey_type(priv),
-           sshkey_type(certpub));
+       if ((helper = helper_by_key(priv)) == NULL || helper->fd == -1)
+               fatal_f("no helper for %s key", sshkey_type(priv));
+
+       debug3_f("private key type %s cert type %s on provider %s",
+           sshkey_type(priv), sshkey_type(certpub), helper->path);
+
        *certprivp = NULL;
        if (!sshkey_is_cert(certpub) || sshkey_is_cert(priv) ||
            !sshkey_equal_public(priv, certpub)) {
@@ -471,95 +308,24 @@ pkcs11_make_cert(const struct sshkey *priv,
                return SSH_ERR_INVALID_ARGUMENT;
        }
        *certprivp = NULL;
-       if (priv->type == KEY_RSA) {
-               if ((rsa_priv = EVP_PKEY_get1_RSA(priv->pkey)) == NULL)
-                       fatal_f("no RSA pkey");
-               if ((helper = helper_by_rsa(rsa_priv)) == NULL ||
-                   helper->fd == -1)
-                       fatal_f("no helper for PKCS11 RSA key");
-               if ((r = sshkey_from_private(priv, &ret)) != 0)
-                       fatal_fr(r, "copy key");
-               if ((rsa_cert = EVP_PKEY_get1_RSA(ret->pkey)) == NULL)
-                       fatal_f("no RSA cert pkey");
-               if (RSA_set_method(rsa_cert, helper->rsa_meth) != 1)
-                       fatal_f("RSA_set_method failed");
-               if (helper->nrsa++ >= INT_MAX)
-                       fatal_f("RSA refcount error");
-               if (EVP_PKEY_set1_RSA(ret->pkey, rsa_cert) != 1)
-                       fatal_f("EVP_PKEY_set1_RSA failed");
-               RSA_free(rsa_priv);
-               RSA_free(rsa_cert);
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       } else if (priv->type == KEY_ECDSA) {
-               if ((ec_priv = EVP_PKEY_get1_EC_KEY(priv->pkey)) == NULL)
-                       fatal_f("no EC pkey");
-               if ((helper = helper_by_ec(ec_priv)) == NULL ||
-                   helper->fd == -1)
-                       fatal_f("no helper for PKCS11 EC key");
-               if ((r = sshkey_from_private(priv, &ret)) != 0)
-                       fatal_fr(r, "copy key");
-               if ((ec_cert = EVP_PKEY_get1_EC_KEY(ret->pkey)) == NULL)
-                       fatal_f("no EC cert pkey");
-               if (EC_KEY_set_method(ec_cert, helper->ec_meth) != 1)
-                       fatal_f("EC_KEY_set_method failed");
-               if (helper->nec++ >= INT_MAX)
-                       fatal_f("EC refcount error");
-               if (EVP_PKEY_set1_EC_KEY(ret->pkey, ec_cert) != 1)
-                       fatal_f("EVP_PKEY_set1_EC_KEY failed");
-               EC_KEY_free(ec_priv);
-               EC_KEY_free(ec_cert);
-#endif
-       } else
-               fatal_f("unknown key type %s", sshkey_type(priv));
+       if ((r = sshkey_from_private(priv, &ret)) != 0)
+               fatal_fr(r, "copy key");
 
        ret->flags |= SSHKEY_FLAG_EXT;
        if ((r = sshkey_to_certified(ret)) != 0 ||
            (r = sshkey_cert_copy(certpub, ret)) != 0)
                fatal_fr(r, "graft certificate");
-       debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA",
-           helper->path, helper->nrsa, helper->nec);
+
+       helper_add_key(helper, ret);
+
+       debug3_f("provider %s: %zu remaining keys",
+           helper->path, helper->nkeyblobs);
+
        /* success */
        *certprivp = ret;
        return 0;
 }
 
-static int
-pkcs11_start_helper_methods(struct helper *helper)
-{
-       RSA_METHOD *rsa_meth = NULL;
-       EC_KEY_METHOD *ec_meth = NULL;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       int (*ec_init)(EC_KEY *key);
-       int (*ec_copy)(EC_KEY *dest, const EC_KEY *src);
-       int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp);
-       int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key);
-       int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key);
-       int (*ec_sign)(int, const unsigned char *, int, unsigned char *,
-           unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
-
-       if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL)
-               return -1;
-       EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL);
-       EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign);
-       EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish,
-           &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public);
-       EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish,
-           ec_copy, ec_set_group, ec_set_private, ec_set_public);
-#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */
-
-       if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL)
-               fatal_f("RSA_meth_dup failed");
-       helper->rsa_finish = RSA_meth_get_finish(rsa_meth);
-       if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") ||
-           !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) ||
-           !RSA_meth_set_finish(rsa_meth, rsa_finish))
-               fatal_f("failed to prepare method");
-
-       helper->ec_meth = ec_meth;
-       helper->rsa_meth = rsa_meth;
-       return 0;
-}
-
 static struct helper *
 pkcs11_start_helper(const char *path)
 {
@@ -576,19 +342,10 @@ pkcs11_start_helper(const char *path)
                return NULL;
        }
        helper = xcalloc(1, sizeof(*helper));
-       if (pkcs11_start_helper_methods(helper) == -1) {
-               error_f("pkcs11_start_helper_methods failed");
-               goto fail;
-       }
        if ((pid = fork()) == -1) {
                error_f("fork: %s", strerror(errno));
- fail:
                close(pair[0]);
                close(pair[1]);
-               RSA_meth_free(helper->rsa_meth);
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-               EC_KEY_METHOD_free(helper->ec_meth);
-#endif
                free(helper);
                return NULL;
        } else if (pid == 0) {
@@ -628,10 +385,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
 {
        struct sshkey *k;
        int r, type;
-       u_char *blob;
        char *label;
-       size_t blen;
-       u_int nkeys, i;
+       u_int ret = -1, nkeys, i;
        struct sshbuf *msg;
        struct helper *helper;
 
@@ -639,6 +394,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
            (helper = pkcs11_start_helper(name)) == NULL)
                return -1;
 
+       debug3_f("add %s", helper->path);
+
        if ((msg = sshbuf_new()) == NULL)
                fatal_f("sshbuf_new failed");
        if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 ||
@@ -649,35 +406,39 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp,
        sshbuf_reset(msg);
 
        type = recv_msg(helper->fd, msg);
+       debug3_f("response %d", type);
        if (type == SSH2_AGENT_IDENTITIES_ANSWER) {
                if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
                        fatal_fr(r, "parse nkeys");
+               debug3_f("helper return %u keys", nkeys);
                *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
                if (labelsp)
                        *labelsp = xcalloc(nkeys, sizeof(char *));
                for (i = 0; i < nkeys; i++) {
                        /* XXX clean up properly instead of fatal() */
-                       if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
+                       if ((r = sshkey_froms(msg, &k)) != 0 ||
                            (r = sshbuf_get_cstring(msg, &label, NULL)) != 0)
                                fatal_fr(r, "parse key");
-                       if ((r = sshkey_from_blob(blob, blen, &k)) != 0)
-                               fatal_fr(r, "decode key");
-                       wrap_key(helper, k);
+                       k->flags |= SSHKEY_FLAG_EXT;
+                       helper_add_key(helper, k);
                        (*keysp)[i] = k;
                        if (labelsp)
                                (*labelsp)[i] = label;
                        else
                                free(label);
-                       free(blob);
                }
+               /* success */
+               ret = 0;
        } else if (type == SSH2_AGENT_FAILURE) {
                if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
-                       nkeys = -1;
-       } else {
-               nkeys = -1;
+                       error_fr(r, "failed to parse failure response");
+       }
+       if (ret != 0) {
+               debug_f("no keys; terminate helper");
+               helper_terminate(helper);
        }
        sshbuf_free(msg);
-       return (nkeys);
+       return ret == 0 ? (int)nkeys : -1;
 }
 
 int
@@ -694,4 +455,39 @@ pkcs11_del_provider(char *name)
                helper_terminate(helper);
        return 0;
 }
-#endif /* ENABLE_PKCS11 */
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+       struct helper *helper;
+       struct sshbuf *keyblob = NULL;
+       size_t i;
+       int r, found = 0;
+
+       debug3_f("free %s key", sshkey_type(key));
+
+       if ((helper = helper_by_key(key)) == NULL || helper->fd == -1)
+               fatal_f("no helper for %s key", sshkey_type(key));
+       if ((keyblob = sshbuf_new()) == NULL)
+               fatal_f("sshbuf_new failed");
+       if ((r = sshkey_putb(key, keyblob)) != 0)
+               fatal_fr(r, "serialise key");
+
+       /* repack keys */
+       for (i = 0; i < helper->nkeyblobs; i++) {
+               if (sshbuf_equals(keyblob, helper->keyblobs[i]) == 0) {
+                       if (found)
+                               fatal_f("key recorded more than once");
+                       found = 1;
+               } else if (found)
+                       helper->keyblobs[i - 1] = helper->keyblobs[i];
+       }
+       if (found) {
+               helper->keyblobs = xrecallocarray(helper->keyblobs,
+                   helper->nkeyblobs, helper->nkeyblobs - 1,
+                   sizeof(*helper->keyblobs));
+               helper->nkeyblobs--;
+       }
+       if (helper->nkeyblobs == 0)
+               helper_terminate(helper);
+}
index a8154f21c058c2f3137e84aae733e62e4a48d49c..2d818b8970a47f1acab3784fcf009709a97b4192 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11-helper.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11-helper.c,v 1.28 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  *
@@ -22,8 +22,6 @@
 # include <sys/time.h>
 #endif
 
-#include "openbsd-compat/sys-queue.h"
-
 #include <stdlib.h>
 #include <errno.h>
 #ifdef HAVE_POLL_H
 
 #ifdef ENABLE_PKCS11
 
-#ifdef WITH_OPENSSL
-#include <openssl/evp.h>
-#include <openssl/ec.h>
-#include <openssl/rsa.h>
-
 /* borrows code from sftp-server and ssh-agent */
 
-struct pkcs11_keyinfo {
-       struct sshkey   *key;
-       char            *providername, *label;
-       TAILQ_ENTRY(pkcs11_keyinfo) next;
-};
-
-TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
+static char *providername; /* Provider for this helper */
 
 #define MAX_MSG_LENGTH         10240 /*XXX*/
 
@@ -65,50 +52,6 @@ TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
 struct sshbuf *iqueue;
 struct sshbuf *oqueue;
 
-static void
-add_key(struct sshkey *k, char *name, char *label)
-{
-       struct pkcs11_keyinfo *ki;
-
-       ki = xcalloc(1, sizeof(*ki));
-       ki->providername = xstrdup(name);
-       ki->key = k;
-       ki->label = xstrdup(label);
-       TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
-}
-
-static void
-del_keys_by_name(char *name)
-{
-       struct pkcs11_keyinfo *ki, *nxt;
-
-       for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) {
-               nxt = TAILQ_NEXT(ki, next);
-               if (!strcmp(ki->providername, name)) {
-                       TAILQ_REMOVE(&pkcs11_keylist, ki, next);
-                       free(ki->providername);
-                       free(ki->label);
-                       sshkey_free(ki->key);
-                       free(ki);
-               }
-       }
-}
-
-/* lookup matching 'private' key */
-static struct sshkey *
-lookup_key(struct sshkey *k)
-{
-       struct pkcs11_keyinfo *ki;
-
-       TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
-               debug("check %s %s %s", sshkey_type(ki->key),
-                   ki->providername, ki->label);
-               if (sshkey_equal(k, ki->key))
-                       return (ki->key);
-       }
-       return (NULL);
-}
-
 static void
 send_msg(struct sshbuf *m)
 {
@@ -121,34 +64,32 @@ send_msg(struct sshbuf *m)
 static void
 process_add(void)
 {
-       char *name, *pin;
+       char *pin;
        struct sshkey **keys = NULL;
        int r, i, nkeys;
-       u_char *blob;
-       size_t blen;
        struct sshbuf *msg;
        char **labels = NULL;
 
+       if (providername != NULL)
+               fatal_f("provider already set");
        if ((msg = sshbuf_new()) == NULL)
                fatal_f("sshbuf_new failed");
-       if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
+       if ((r = sshbuf_get_cstring(iqueue, &providername, NULL)) != 0 ||
            (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
                fatal_fr(r, "parse");
-       if ((nkeys = pkcs11_add_provider(name, pin, &keys, &labels)) > 0) {
+       debug3_f("add %s", providername);
+       if ((nkeys = pkcs11_add_provider(providername, pin,
+           &keys, &labels)) > 0) {
                if ((r = sshbuf_put_u8(msg,
                    SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
                    (r = sshbuf_put_u32(msg, nkeys)) != 0)
                        fatal_fr(r, "compose");
                for (i = 0; i < nkeys; i++) {
-                       if ((r = sshkey_to_blob(keys[i], &blob, &blen)) != 0) {
-                               debug_fr(r, "encode key");
-                               continue;
-                       }
-                       if ((r = sshbuf_put_string(msg, blob, blen)) != 0 ||
+                       if ((r = sshkey_puts(keys[i], msg)) != 0 ||
                            (r = sshbuf_put_cstring(msg, labels[i])) != 0)
                                fatal_fr(r, "compose key");
-                       free(blob);
-                       add_key(keys[i], name, labels[i]);
+                       debug3_f("%s: %s \"%s\"", providername,
+                           sshkey_type(keys[i]), labels[i]);
                        free(labels[i]);
                }
        } else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0 ||
@@ -157,95 +98,39 @@ process_add(void)
        free(labels);
        free(keys); /* keys themselves are transferred to pkcs11_keylist */
        free(pin);
-       free(name);
        send_msg(msg);
        sshbuf_free(msg);
 }
 
 static void
-process_del(void)
+process_sign(void)
 {
-       char *name, *pin;
+       const u_char *data;
+       u_char *signature = NULL;
+       size_t dlen, slen = 0;
+       u_int compat;
+       int r, ok = -1;
+       struct sshkey *key = NULL;
        struct sshbuf *msg;
-       int r;
+       char *alg = NULL;
 
-       if ((msg = sshbuf_new()) == NULL)
-               fatal_f("sshbuf_new failed");
-       if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
-           (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0)
+       if ((r = sshkey_froms(iqueue, &key)) != 0 ||
+           (r = sshbuf_get_string_direct(iqueue, &data, &dlen)) != 0 ||
+           (r = sshbuf_get_cstring(iqueue, &alg, NULL)) != 0 ||
+           (r = sshbuf_get_u32(iqueue, &compat)) != 0)
                fatal_fr(r, "parse");
-       del_keys_by_name(name);
-       if ((r = sshbuf_put_u8(msg, pkcs11_del_provider(name) == 0 ?
-           SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0)
-               fatal_fr(r, "compose");
-       free(pin);
-       free(name);
-       send_msg(msg);
-       sshbuf_free(msg);
-}
 
-static void
-process_sign(void)
-{
-       u_char *blob, *data, *signature = NULL;
-       size_t blen, dlen;
-       u_int slen = 0;
-       int len, r, ok = -1;
-       struct sshkey *key = NULL, *found;
-       struct sshbuf *msg;
-#ifdef WITH_OPENSSL
-       RSA *rsa = NULL;
-#ifdef OPENSSL_HAS_ECC
-       EC_KEY *ecdsa = NULL;
-#endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
-
-       /* XXX support SHA2 signature flags */
-       if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 ||
-           (r = sshbuf_get_string(iqueue, &data, &dlen)) != 0 ||
-           (r = sshbuf_get_u32(iqueue, NULL)) != 0)
-               fatal_fr(r, "parse");
+       if (*alg == '\0') {
+               free(alg);
+               alg = NULL;
+       }
 
-       if ((r = sshkey_from_blob(blob, blen, &key)) != 0)
-               fatal_fr(r, "decode key");
-       if ((found = lookup_key(key)) == NULL)
+       if ((r = pkcs11_sign(key, &signature, &slen, data, dlen,
+           alg, NULL, NULL, compat)) != 0) {
+               error_fr(r, "sign %s", sshkey_type(key));
                goto reply;
-
-       /* XXX use pkey API properly for signing */
-       switch (key->type) {
-#ifdef WITH_OPENSSL
-       case KEY_RSA:
-               if ((rsa = EVP_PKEY_get1_RSA(found->pkey)) == NULL)
-                       fatal_f("no RSA in pkey");
-               if ((len = RSA_size(rsa)) < 0)
-                       fatal_f("bad RSA length");
-               signature = xmalloc(len);
-               if ((len = RSA_private_encrypt(dlen, data, signature,
-                   rsa, RSA_PKCS1_PADDING)) < 0) {
-                       error_f("RSA_private_encrypt failed");
-                       goto reply;
-               }
-               slen = (u_int)len;
-               break;
-#ifdef OPENSSL_HAS_ECC
-       case KEY_ECDSA:
-               if ((ecdsa = EVP_PKEY_get1_EC_KEY(found->pkey)) == NULL)
-                       fatal_f("no ECDSA in pkey");
-               if ((len = ECDSA_size(ecdsa)) < 0)
-                       fatal_f("bad ECDSA length");
-               slen = (u_int)len;
-               signature = xmalloc(slen);
-               /* "The parameter type is ignored." */
-               if (!ECDSA_sign(-1, data, dlen, signature, &slen, ecdsa)) {
-                       error_f("ECDSA_sign failed");
-                       goto reply;
-               }
-               break;
-#endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
-       default:
-               fatal_f("unsupported key type %d", key->type);
        }
+
        /* success */
        ok = 0;
  reply:
@@ -260,12 +145,7 @@ process_sign(void)
                        fatal_fr(r, "compose failure response");
        }
        sshkey_free(key);
-       RSA_free(rsa);
-#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
-       EC_KEY_free(ecdsa);
-#endif
-       free(data);
-       free(blob);
+       free(alg);
        free(signature);
        send_msg(msg);
        sshbuf_free(msg);
@@ -301,10 +181,6 @@ process(void)
                debug("process_add");
                process_add();
                break;
-       case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
-               debug("process_del");
-               process_del();
-               break;
        case SSH2_AGENTC_SIGN_REQUEST:
                debug("process_sign");
                process_sign();
@@ -336,7 +212,6 @@ cleanup_exit(int i)
        _exit(i);
 }
 
-
 int
 main(int argc, char **argv)
 {
@@ -350,7 +225,6 @@ main(int argc, char **argv)
 
        __progname = ssh_get_progname(argv[0]);
        seed_rng();
-       TAILQ_INIT(&pkcs11_keylist);
 
        log_init(__progname, log_level, log_facility, log_stderr);
 
@@ -439,22 +313,23 @@ main(int argc, char **argv)
                        fatal_fr(r, "reserve");
        }
 }
-
-#else /* WITH_OPENSSL */
-void
-cleanup_exit(int i)
+#else /* ENABLE_PKCS11 */
+/* stubs */
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
-       _exit(i);
+       return SSH_ERR_INTERNAL_ERROR;
 }
 
-int
-main(int argc, char **argv)
+void
+pkcs11_key_free(struct sshkey *key)
 {
-       fprintf(stderr, "PKCS#11 code is not enabled\n");
-       return 1;
 }
-#endif /* WITH_OPENSSL */
-#else /* ENABLE_PKCS11 */
+
 int
 main(int argc, char **argv)
 {
index 31b9360f0adbc620296610307dbedea27b7426f4..147c52049500367aa4811c3a94b6c6b9cba8c612 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.c,v 1.64 2024/09/20 02:00:46 jsg Exp $ */
+/* $OpenBSD: ssh-pkcs11.c,v 1.65 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
 #define CRYPTOKI_COMPAT
 #include "pkcs11.h"
 
+#define SSHKEY_INTERNAL
+#include "sshkey.h"
+
 #include "log.h"
 #include "misc.h"
-#include "sshkey.h"
+#include "sshbuf.h"
 #include "ssh-pkcs11.h"
 #include "digest.h"
 #include "xmalloc.h"
@@ -71,15 +74,19 @@ struct pkcs11_provider {
 TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
 
 struct pkcs11_key {
+       struct sshbuf           *keyblob;
        struct pkcs11_provider  *provider;
        CK_ULONG                slotidx;
        char                    *keyid;
        int                     keyid_len;
+       TAILQ_ENTRY(pkcs11_key) next;
 };
 
+TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */
+
 int pkcs11_interactive = 0;
 
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
+#ifdef WITH_OPENSSL
 static void
 ossl_error(const char *msg)
 {
@@ -89,15 +96,7 @@ ossl_error(const char *msg)
        while ((e = ERR_get_error()) != 0)
                error_f("libcrypto error: %s", ERR_error_string(e, NULL));
 }
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
-
-int
-pkcs11_init(int interactive)
-{
-       pkcs11_interactive = interactive;
-       TAILQ_INIT(&pkcs11_providers);
-       return (0);
-}
+#endif
 
 /*
  * finalize a provider shared library, it's no longer usable.
@@ -146,19 +145,6 @@ pkcs11_provider_unref(struct pkcs11_provider *p)
        }
 }
 
-/* unregister all providers, keys might still point to the providers */
-void
-pkcs11_terminate(void)
-{
-       struct pkcs11_provider *p;
-
-       while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
-               TAILQ_REMOVE(&pkcs11_providers, p, next);
-               pkcs11_provider_finalize(p);
-               pkcs11_provider_unref(p);
-       }
-}
-
 /* lookup provider by name */
 static struct pkcs11_provider *
 pkcs11_provider_lookup(char *provider_id)
@@ -188,26 +174,16 @@ pkcs11_del_provider(char *provider_id)
        return (-1);
 }
 
-static RSA_METHOD *rsa_method;
-static int rsa_idx = 0;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-static EC_KEY_METHOD *ec_key_method;
-static int ec_key_idx = 0;
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
-
 /* release a wrapped object */
 static void
-pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
-    long argl, void *argp)
+pkcs11_k11_free(struct pkcs11_key *k11)
 {
-       struct pkcs11_key       *k11 = ptr;
-
-       debug_f("parent %p ptr %p idx %d", parent, ptr, idx);
        if (k11 == NULL)
                return;
        if (k11->provider)
                pkcs11_provider_unref(k11->provider);
        free(k11->keyid);
+       sshbuf_free(k11->keyblob);
        free(k11);
 }
 
@@ -417,214 +393,324 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type)
        return (0);
 }
 
-/* openssl callback doing the actual signing operation */
+/* record the key information later use lookup by keyblob */
 static int
-pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
-    int padding)
+pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx,
+    CK_ATTRIBUTE *keyid_attrib, struct sshkey *key)
 {
-       struct pkcs11_key       *k11;
-       struct pkcs11_slotinfo  *si;
-       CK_FUNCTION_LIST        *f;
-       CK_ULONG                tlen = 0;
-       CK_RV                   rv;
-       int                     rval = -1;
-
-       if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) {
-               error("RSA_get_ex_data failed");
-               return (-1);
+       struct sshbuf *keyblob;
+       struct pkcs11_key *k11;
+       int r;
+       char *hex;
+
+       hex = tohex(keyid_attrib->pValue, keyid_attrib->ulValueLen);
+       debug_f("%s key: provider %s slot %lu keyid %s",
+           sshkey_type(key), provider->name, (u_long)slotidx, hex);
+       free(hex);
+
+       if ((keyblob = sshbuf_new()) == NULL)
+               fatal_f("sshbuf_new failed");
+       if ((r = sshkey_putb(key, keyblob)) != 0)
+               fatal_fr(r, "sshkey_putb");
+
+       /* Check if we've already recorded this key in a different slot */
+       TAILQ_FOREACH(k11, &pkcs11_keys, next) {
+               if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
+                       hex = tohex(k11->keyid, k11->keyid_len);
+                       debug_f("Already seen this key at "
+                           "provider %s slot %lu keyid %s",
+                           k11->provider->name, k11->slotidx, hex);
+                       free(hex);
+                       sshbuf_free(keyblob);
+                       return -1;
+               }
        }
 
-       if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
-               error("pkcs11_get_key failed");
-               return (-1);
+       k11 = xcalloc(1, sizeof(*k11));
+       k11->provider = provider;
+       k11->keyblob = keyblob;
+       provider->refcount++;   /* provider referenced by RSA key */
+       k11->slotidx = slotidx;
+       /* identify key object on smartcard */
+       k11->keyid_len = keyid_attrib->ulValueLen;
+       if (k11->keyid_len > 0) {
+               k11->keyid = xmalloc(k11->keyid_len);
+               memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
        }
+       TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next);
 
-       f = k11->provider->function_list;
-       si = &k11->provider->slotinfo[k11->slotidx];
-       tlen = RSA_size(rsa);
-
-       /* XXX handle CKR_BUFFER_TOO_SMALL */
-       rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
-       if (rv == CKR_OK)
-               rval = tlen;
-       else
-               error("C_Sign failed: %lu", rv);
-
-       return (rval);
+       return 0;
 }
 
-static int
-pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
-    int padding)
+/* retrieve the key information by keyblob */
+static struct pkcs11_key *
+pkcs11_lookup_key(struct sshkey *key)
 {
-       return (-1);
+       struct pkcs11_key *k11, *found = NULL;
+       struct sshbuf *keyblob;
+       int r;
+
+       if ((keyblob = sshbuf_new()) == NULL)
+               fatal_f("sshbuf_new failed");
+       if ((r = sshkey_putb(key, keyblob)) != 0)
+               fatal_fr(r, "sshkey_putb");
+       TAILQ_FOREACH(k11, &pkcs11_keys, next) {
+               if (sshbuf_equals(k11->keyblob, keyblob) == 0) {
+                       found = k11;
+                       break;
+               }
+       }
+       sshbuf_free(keyblob);
+       return found;
 }
 
+#ifdef WITH_OPENSSL
+/*
+ * 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
-pkcs11_rsa_start_wrapper(void)
+rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
 {
-       if (rsa_method != NULL)
-               return (0);
-       rsa_method = RSA_meth_dup(RSA_get_default_method());
-       if (rsa_method == NULL)
-               return (-1);
-       rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa",
-           NULL, NULL, pkcs11_k11_free);
-       if (rsa_idx == -1)
-               return (-1);
-       if (!RSA_meth_set1_name(rsa_method, "pkcs11") ||
-           !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) ||
-           !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) {
-               error_f("setup pkcs11 method failed");
-               return (-1);
+       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);
+       return 0;
 }
 
-/* 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)
+pkcs11_sign_rsa(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
        struct pkcs11_key       *k11;
+       struct pkcs11_slotinfo  *si;
+       CK_FUNCTION_LIST        *f;
+       CK_ULONG                slen = 0;
+       CK_RV                   rv;
+       int                     hashalg, r, diff, siglen, ret = -1;
+       u_char                  *oid_dgst = NULL, *sig = NULL;
+       size_t                  dgst_len, oid_len, oid_dgst_len = 0;
+       const u_char            *oid;
 
-       if (pkcs11_rsa_start_wrapper() == -1)
-               return (-1);
+       if (sigp != NULL)
+               *sigp = 0;
+       if (lenp != NULL)
+               *lenp = 0;
 
-       k11 = xcalloc(1, sizeof(*k11));
-       k11->provider = provider;
-       provider->refcount++;   /* provider referenced by RSA key */
-       k11->slotidx = slotidx;
-       /* identify key object on smartcard */
-       k11->keyid_len = keyid_attrib->ulValueLen;
-       if (k11->keyid_len > 0) {
-               k11->keyid = xmalloc(k11->keyid_len);
-               memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
+       if ((k11 = pkcs11_lookup_key(key)) == NULL) {
+               error_f("no key found");
+               return SSH_ERR_KEY_NOT_FOUND;
        }
 
-       if (RSA_set_method(rsa, rsa_method) != 1)
-               fatal_f("RSA_set_method failed");
-       if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1)
-               fatal_f("RSA_set_ex_data failed");
-       return (0);
+       debug3_f("sign with alg \"%s\" using provider %s slotidx %lu",
+           alg == NULL ? "" : alg, k11->provider->name, (u_long)k11->slotidx);
+
+       if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) {
+               error("pkcs11_get_key failed");
+               return SSH_ERR_AGENT_FAILURE;
+       }
+
+       f = k11->provider->function_list;
+       si = &k11->provider->slotinfo[k11->slotidx];
+
+       if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
+               return SSH_ERR_INVALID_ARGUMENT;
+       sig = xmalloc(siglen);
+       slen = (CK_ULONG)siglen;
+
+       /* Determine hash algorithm and OID for signature */
+       if (alg == NULL || *alg == '\0')
+               hashalg = SSH_DIGEST_SHA1;
+       else if ((hashalg = ssh_rsa_hash_id_from_keyname(alg)) == -1)
+               fatal_f("couldn't determine RSA hash alg \"%s\"", alg);
+       if ((r = rsa_hash_alg_oid(hashalg, &oid, &oid_len)) != 0)
+               fatal_fr(r, "rsa_hash_alg_oid failed");
+       if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
+               fatal_f("bad hash alg %d", hashalg);
+
+       /* Prepare { oid || digest } */
+       oid_dgst_len = oid_len + dgst_len;
+       oid_dgst = xcalloc(1, oid_dgst_len);
+       memcpy(oid_dgst, oid, oid_len);
+       if ((r = ssh_digest_memory(hashalg, data, datalen,
+           oid_dgst + oid_len, dgst_len)) == -1)
+               fatal_fr(r, "hash failed");
+
+       /* XXX handle CKR_BUFFER_TOO_SMALL */
+       if ((rv = f->C_Sign(si->session, (CK_BYTE *)oid_dgst,
+           oid_dgst_len, sig, &slen)) != CKR_OK) {
+               error("C_Sign failed: %lu", rv);
+               goto done;
+       }
+
+       if (slen < (CK_ULONG)siglen) {
+               diff = siglen - slen;
+               debug3_f("repack %lu < %d (diff %d)",
+                   (u_long)slen, siglen, diff);
+               memmove(sig + diff, sig, slen);
+               explicit_bzero(sig, diff);
+       } else if (slen > (size_t)siglen)
+               fatal_f("bad C_Sign length");
+
+       if ((ret = ssh_rsa_encode_store_sig(hashalg, sig, siglen,
+           sigp, lenp)) != 0)
+               fatal_fr(ret, "couldn't store signature");
+
+       /* success */
+       ret = 0;
+ done:
+       freezero(oid_dgst, oid_dgst_len);
+       free(sig);
+       return ret;
 }
 
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-/* openssl callback doing the actual signing operation */
-static ECDSA_SIG *
-ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
-    const BIGNUM *rp, EC_KEY *ec)
+#ifdef OPENSSL_HAS_ECC
+static int
+pkcs11_sign_ecdsa(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
 {
        struct pkcs11_key       *k11;
        struct pkcs11_slotinfo  *si;
        CK_FUNCTION_LIST        *f;
-       CK_ULONG                siglen = 0, bnlen;
+       CK_ULONG                slen = 0, bnlen;
        CK_RV                   rv;
-       ECDSA_SIG               *ret = NULL;
-       u_char                  *sig;
-       BIGNUM                  *r = NULL, *s = NULL;
+       BIGNUM                  *sig_r = NULL, *sig_s = NULL;
+       u_char                  *sig = NULL, *dgst = NULL;
+       size_t                  dgst_len = 0;
+       int                     hashalg, ret = -1, r, siglen;
 
-       if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) {
-               ossl_error("EC_KEY_get_ex_data failed for ec");
-               return (NULL);
+       if (sigp != NULL)
+               *sigp = 0;
+       if (lenp != NULL)
+               *lenp = 0;
+
+       if ((k11 = pkcs11_lookup_key(key)) == NULL) {
+               error_f("no key found");
+               return SSH_ERR_KEY_NOT_FOUND;
        }
 
        if (pkcs11_get_key(k11, CKM_ECDSA) == -1) {
                error("pkcs11_get_key failed");
-               return (NULL);
+               return SSH_ERR_AGENT_FAILURE;
        }
 
+       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];
 
-       siglen = ECDSA_size(ec);
+       /* Prepare digest to be signed */
+       if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
+               fatal_f("couldn't determine ECDSA hash alg");
+       if ((dgst_len = ssh_digest_bytes(hashalg)) == 0)
+               fatal_f("bad hash alg %d", hashalg);
+       dgst = xcalloc(1, dgst_len);
+       if ((r = ssh_digest_memory(hashalg, data, datalen,
+           dgst, dgst_len)) == -1)
+               fatal_fr(r, "hash failed");
+
+       if ((siglen = EVP_PKEY_size(key->pkey)) <= 0)
+               return SSH_ERR_INVALID_ARGUMENT;
        sig = xmalloc(siglen);
+       slen = (CK_ULONG)siglen;
 
        /* XXX handle CKR_BUFFER_TOO_SMALL */
-       rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen);
+       rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &slen);
        if (rv != CKR_OK) {
                error("C_Sign failed: %lu", rv);
                goto done;
        }
-       if (siglen < 64 || siglen > 132 || siglen % 2) {
-               error_f("bad signature length: %lu", (u_long)siglen);
-               goto done;
-       }
-       bnlen = siglen/2;
-       if ((ret = ECDSA_SIG_new()) == NULL) {
-               error("ECDSA_SIG_new failed");
+       if (slen < 64 || slen > 132 || slen % 2) {
+               error_f("bad signature length: %lu", (u_long)slen);
                goto done;
        }
-       if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
-           (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
+       bnlen = slen/2;
+       if ((sig_r = BN_bin2bn(sig, bnlen, NULL)) == NULL ||
+           (sig_s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) {
                ossl_error("BN_bin2bn failed");
-               ECDSA_SIG_free(ret);
-               ret = NULL;
                goto done;
        }
-       if (!ECDSA_SIG_set0(ret, r, s)) {
-               error_f("ECDSA_SIG_set0 failed");
-               ECDSA_SIG_free(ret);
-               ret = NULL;
-               goto done;
-       }
-       r = s = NULL; /* now owned by ret */
+
+       if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s,
+           sigp, lenp)) != 0)
+               fatal_fr(ret, "couldn't store signature");
+
        /* success */
+       ret = 0;
  done:
-       BN_free(r);
-       BN_free(s);
+       freezero(dgst, dgst_len);
+       BN_free(sig_r);
+       BN_free(sig_s);
        free(sig);
-
-       return (ret);
+       return ret;
 }
-
-static int
-pkcs11_ecdsa_start_wrapper(void)
-{
-       int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
-           unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
-
-       if (ec_key_method != NULL)
-               return (0);
-       ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa",
-           NULL, NULL, pkcs11_k11_free);
-       if (ec_key_idx == -1)
-               return (-1);
-       ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
-       if (ec_key_method == NULL)
-               return (-1);
-       EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL);
-       EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign);
-       return (0);
-}
-
-static int
-pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
-    CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
-{
-       struct pkcs11_key       *k11;
-
-       if (pkcs11_ecdsa_start_wrapper() == -1)
-               return (-1);
-
-       k11 = xcalloc(1, sizeof(*k11));
-       k11->provider = provider;
-       provider->refcount++;   /* provider referenced by ECDSA key */
-       k11->slotidx = slotidx;
-       /* identify key object on smartcard */
-       k11->keyid_len = keyid_attrib->ulValueLen;
-       if (k11->keyid_len > 0) {
-               k11->keyid = xmalloc(k11->keyid_len);
-               memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
-       }
-       if (EC_KEY_set_method(ec, ec_key_method) != 1)
-               fatal_f("EC_KEY_set_method failed");
-       if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1)
-               fatal_f("EC_KEY_set_ex_data failed");
-
-       return (0);
-}
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
+#endif /* OPENSSL_HAS_ECC */
+#endif /* WITH_OPENSSL */
 
 /* remove trailing spaces */
 static char *
@@ -702,7 +788,8 @@ pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key)
        return (0);
 }
 
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
+#ifdef WITH_OPENSSL
+#ifdef OPENSSL_HAS_ECC
 static struct sshkey *
 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
     CK_OBJECT_HANDLE *obj)
@@ -716,8 +803,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
        EC_GROUP                *group = NULL;
        struct sshkey           *key = NULL;
        const unsigned char     *attrp = NULL;
-       int                      i;
-       int                      nid;
+       int                      success = -1, r, i, nid;
 
        memset(&key_attr, 0, sizeof(key_attr));
        key_attr[0].type = CKA_ID;
@@ -791,6 +877,11 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                ossl_error("o2i_ECPublicKey failed");
                goto fail;
        }
+       if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
+           EC_KEY_get0_public_key(ec))) != 0) {
+               error_fr(r, "invalid EC key");
+               goto fail;
+       }
 
        nid = sshkey_ecdsa_key_to_nid(ec);
        if (nid < 0) {
@@ -798,9 +889,6 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                goto fail;
        }
 
-       if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
-               goto fail;
-
        key = sshkey_new(KEY_UNSPEC);
        if (key == NULL) {
                error("sshkey_new failed");
@@ -815,8 +903,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
        key->ecdsa_nid = nid;
        key->type = KEY_ECDSA;
        key->flags |= SSHKEY_FLAG_EXT;
-
+       if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
+               goto fail;
+       /* success */
+       success = 0;
 fail:
+       if (success != 0) {
+               sshkey_free(key);
+               key = NULL;
+       }
        for (i = 0; i < 3; i++)
                free(key_attr[i].pValue);
        if (ec)
@@ -828,7 +923,7 @@ fail:
 
        return (key);
 }
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
+#endif /* OPENSSL_HAS_ECC */
 
 static struct sshkey *
 pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
@@ -841,7 +936,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
        RSA                     *rsa = NULL;
        BIGNUM                  *rsa_n, *rsa_e;
        struct sshkey           *key = NULL;
-       int                      i;
+       int                      i, success = -1;
 
        memset(&key_attr, 0, sizeof(key_attr));
        key_attr[0].type = CKA_ID;
@@ -897,9 +992,6 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                fatal_f("set key");
        rsa_n = rsa_e = NULL; /* transferred */
 
-       if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
-               goto fail;
-
        key = sshkey_new(KEY_UNSPEC);
        if (key == NULL) {
                error("sshkey_new failed");
@@ -913,13 +1005,24 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                fatal("EVP_PKEY_set1_RSA failed");
        key->type = KEY_RSA;
        key->flags |= SSHKEY_FLAG_EXT;
-
+       if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+               error_f("RSA key too small %d < minumum %d",
+                   EVP_PKEY_bits(key->pkey), SSH_RSA_MINIMUM_MODULUS_SIZE);
+               goto fail;
+       }
+       if (pkcs11_record_key(p, slotidx, &key_attr[0], key))
+               goto fail;
+       /* success */
+       success = 0;
 fail:
        for (i = 0; i < 3; i++)
                free(key_attr[i].pValue);
        RSA_free(rsa);
-
-       return (key);
+       if (success != 0) {
+               sshkey_free(key);
+               key = NULL;
+       }
+       return key;
 }
 
 static int
@@ -934,14 +1037,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
        X509_NAME               *x509_name = NULL;
        EVP_PKEY                *evp;
        RSA                     *rsa = NULL;
-#ifdef OPENSSL_HAS_ECC
        EC_KEY                  *ec = NULL;
-#endif
        struct sshkey           *key = NULL;
-       int                      i;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
-       int                      nid;
-#endif
+       int                      r, i, nid, success = -1;
        const u_char            *cp;
        char                    *subject = NULL;
 
@@ -1015,9 +1113,6 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                        goto out;
                }
 
-               if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
-                       goto out;
-
                key = sshkey_new(KEY_UNSPEC);
                if (key == NULL) {
                        error("sshkey_new failed");
@@ -1031,7 +1126,16 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                        fatal("EVP_PKEY_set1_RSA failed");
                key->type = KEY_RSA;
                key->flags |= SSHKEY_FLAG_EXT;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
+               if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+                       error_f("RSA key too small %d < minumum %d",
+                           EVP_PKEY_bits(key->pkey),
+                           SSH_RSA_MINIMUM_MODULUS_SIZE);
+                       goto out;
+               }
+               if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
+                       goto out;
+               /* success */
+               success = 0;
        } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
                if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
                        error("invalid x509; no ec key");
@@ -1041,16 +1145,17 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                        error("EC_KEY_dup failed");
                        goto out;
                }
-
+               if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec),
+                   EC_KEY_get0_public_key(ec))) != 0) {
+                       error_fr(r, "invalid EC key");
+                       goto out;
+               }
                nid = sshkey_ecdsa_key_to_nid(ec);
                if (nid < 0) {
                        error("couldn't get curve nid");
                        goto out;
                }
 
-               if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
-                       goto out;
-
                key = sshkey_new(KEY_UNSPEC);
                if (key == NULL) {
                        error("sshkey_new failed");
@@ -1065,7 +1170,10 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                key->ecdsa_nid = nid;
                key->type = KEY_ECDSA;
                key->flags |= SSHKEY_FLAG_EXT;
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
+               if (pkcs11_record_key(p, slotidx, &cert_attr[0], key))
+                       goto out;
+               /* success */
+               success = 0;
        } else {
                error("unknown certificate key type");
                goto out;
@@ -1075,10 +1183,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                free(cert_attr[i].pValue);
        X509_free(x509);
        RSA_free(rsa);
-#ifdef OPENSSL_HAS_ECC
        EC_KEY_free(ec);
-#endif
-       if (key == NULL) {
+       if (success != 0 || key == NULL) {
+               sshkey_free(key);
                free(subject);
                return -1;
        }
@@ -1098,6 +1205,7 @@ have_rsa_key(const RSA *rsa)
        return rsa_n != NULL && rsa_e != NULL;
 }
 #endif
+#endif /* WITH_OPENSSL */
 
 static void
 note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context,
@@ -1289,15 +1397,16 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
                case CKK_RSA:
                        key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj);
                        break;
-#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW)
+#if defined(OPENSSL_HAS_ECC)
                case CKK_ECDSA:
                        key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj);
                        break;
-#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
+#endif /* OPENSSL_HAS_ECC */
                default:
                        /* XXX print key type? */
                        key = NULL;
-                       error("skipping unsupported key type");
+                       error("skipping unsupported key type 0x%lx",
+                           (u_long)ck_key_type);
                }
 
                if (key == NULL) {
@@ -1693,6 +1802,35 @@ fail:
        return (ret);
 }
 
+int
+pkcs11_init(int interactive)
+{
+       debug3_f("called, interactive = %d", interactive);
+
+       pkcs11_interactive = interactive;
+       TAILQ_INIT(&pkcs11_providers);
+       TAILQ_INIT(&pkcs11_keys);
+       return (0);
+}
+
+/* unregister all providers, keys might still point to the providers */
+void
+pkcs11_terminate(void)
+{
+       struct pkcs11_provider *p;
+       struct pkcs11_key *k11;
+
+       debug3_f("called");
+
+       while ((k11 = TAILQ_FIRST(&pkcs11_keys)) != NULL)
+               pkcs11_k11_free(k11);
+       while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
+               TAILQ_REMOVE(&pkcs11_providers, p, next);
+               pkcs11_provider_finalize(p);
+               pkcs11_provider_unref(p);
+       }
+}
+
 /*
  * register a new provider and get number of keys hold by the token,
  * fails if provider already exists
@@ -1719,6 +1857,33 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
        return (nkeys);
 }
 
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
+{
+       switch (key->type) {
+       case KEY_RSA:
+       case KEY_RSA_CERT:
+               return pkcs11_sign_rsa(key, sigp, lenp, data, datalen,
+                   alg, sk_provider, sk_pin, compat);
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen,
+                   alg, sk_provider, sk_pin, compat);
+       default:
+               return SSH_ERR_KEY_TYPE_UNKNOWN;
+       }
+}
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+       /* never called */
+}
+
 #ifdef WITH_PKCS11_KEYGEN
 struct sshkey *
 pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label,
index 526022319b4bc9239c23a5512654d70ce7cd122b..f3a03b6fa9138eacc7ccff60805e710164727214 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.h,v 1.7 2023/12/18 14:46:56 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11.h,v 1.8 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  *
 #define        SSH_PKCS11_ERR_PIN_REQUIRED             4
 #define        SSH_PKCS11_ERR_PIN_LOCKED               5
 
+struct sshkey;
+
 int    pkcs11_init(int);
 void   pkcs11_terminate(void);
 int    pkcs11_add_provider(char *, char *, struct sshkey ***, char ***);
 int    pkcs11_del_provider(char *);
+int    pkcs11_sign(struct sshkey *, u_char **, size_t *,
+           const u_char *, size_t, const char *, const char *,
+           const char *, u_int);
+void   pkcs11_key_free(struct sshkey *);
+
 #ifdef WITH_PKCS11_KEYGEN
 struct sshkey *
        pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int,
@@ -35,9 +42,10 @@ struct sshkey *
            u_int32_t *);
 #endif
 
-/* Only available in ssh-pkcs11-client.c so far */
+/* Only available in ssh-pkcs11-client.c */
 int pkcs11_make_cert(const struct sshkey *,
     const struct sshkey *, struct sshkey **);
+
 #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
 #undef ENABLE_PKCS11
 #endif
index 3ad1fddc4e16b4fcd93f931de1526843969e89dd..abc5b17fbeb7152924366241bc88ddccfaf9be6d 100644 (file)
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.80 2024/08/15 00:51:51 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.81 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
@@ -309,8 +309,8 @@ ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
        return r;
 }
 
-static const char *
-rsa_hash_alg_ident(int hash_alg)
+const char *
+ssh_rsa_hash_alg_ident(int hash_alg)
 {
        switch (hash_alg) {
        case SSH_DIGEST_SHA1:
@@ -344,8 +344,8 @@ rsa_hash_id_from_ident(const char *ident)
  * all the cases of rsa_hash_id_from_ident() but also the certificate key
  * types.
  */
-static int
-rsa_hash_id_from_keyname(const char *alg)
+int
+ssh_rsa_hash_id_from_keyname(const char *alg)
 {
        int r;
 
@@ -410,7 +410,6 @@ ssh_rsa_sign(struct sshkey *key,
        size_t diff, len = 0;
        int slen = 0;
        int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
-       struct sshbuf *b = NULL;
 
        if (lenp != NULL)
                *lenp = 0;
@@ -420,7 +419,7 @@ ssh_rsa_sign(struct sshkey *key,
        if (alg == NULL || strlen(alg) == 0)
                hash_alg = SSH_DIGEST_SHA1;
        else
-               hash_alg = rsa_hash_id_from_keyname(alg);
+               hash_alg = ssh_rsa_hash_id_from_keyname(alg);
 
        if (key == NULL || key->pkey == NULL || hash_alg == -1 ||
            sshkey_type_plain(key->type) != KEY_RSA)
@@ -442,16 +441,42 @@ ssh_rsa_sign(struct sshkey *key,
                ret = SSH_ERR_INTERNAL_ERROR;
                goto out;
        }
+       if ((ret = ssh_rsa_encode_store_sig(hash_alg, sig, slen,
+           sigp, lenp)) != 0)
+               goto out;
+
+       /* success */
+       ret = 0;
+ out:
+       freezero(sig, slen);
+       return ret;
+}
 
-       /* encode signature */
+int
+ssh_rsa_encode_store_sig(int hash_alg, const u_char *sig, size_t slen,
+    u_char **sigp, size_t *lenp)
+{
+       struct sshbuf *b = NULL;
+       int ret = SSH_ERR_INTERNAL_ERROR;
+       size_t len;
+
+       if (lenp != NULL)
+               *lenp = 0;
+       if (sigp != NULL)
+               *sigp = NULL;
+
+       /* Encode signature */
        if ((b = sshbuf_new()) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 ||
+       if ((ret = sshbuf_put_cstring(b,
+           ssh_rsa_hash_alg_ident(hash_alg))) != 0 ||
            (ret = sshbuf_put_string(b, sig, slen)) != 0)
                goto out;
        len = sshbuf_len(b);
+
+       /* Store signature */
        if (sigp != NULL) {
                if ((*sigp = malloc(len)) == NULL) {
                        ret = SSH_ERR_ALLOC_FAIL;
@@ -463,7 +488,6 @@ ssh_rsa_sign(struct sshkey *key,
                *lenp = len;
        ret = 0;
  out:
-       freezero(sig, slen);
        sshbuf_free(b);
        return ret;
 }
@@ -502,7 +526,7 @@ ssh_rsa_verify(const struct sshkey *key,
         * legacy reasons, but otherwise the signature type should match.
         */
        if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) {
-               if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) {
+               if ((want_alg = ssh_rsa_hash_id_from_keyname(alg)) == -1) {
                        ret = SSH_ERR_INVALID_ARGUMENT;
                        goto out;
                }
index 9857b632bfcba8e924c4cb1afc7790c92ae99327..806019c46a3dcbc61f33d9adb045bf3f13271b99 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk-helper.c,v 1.14 2022/12/04 11:03:11 dtucker Exp $ */
+/* $OpenBSD: ssh-sk-helper.c,v 1.15 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -45,6 +45,7 @@
 #include "uidswap.h"
 #include "ssherr.h"
 #include "ssh-sk.h"
+#include "ssh-pkcs11.h"
 
 #ifdef ENABLE_SK
 extern char *__progname;
@@ -87,6 +88,22 @@ null_empty(char **s)
        *s = NULL;
 }
 
+/* stubs */
+int
+pkcs11_sign(struct sshkey *key,
+    u_char **sigp, size_t *lenp,
+    const u_char *data, size_t datalen,
+    const char *alg, const char *sk_provider,
+    const char *sk_pin, u_int compat)
+{
+       return SSH_ERR_INTERNAL_ERROR;
+}
+
+void
+pkcs11_key_free(struct sshkey *key)
+{
+}
+
 static struct sshbuf *
 process_sign(struct sshbuf *req)
 {
index 201279faf0f22005ba7d105f23af2db5c2943b70..bc92866db60a9cafa75c7ba29590954c80be423d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sshbuf-misc.c,v 1.20 2025/06/16 09:02:19 dtucker Exp $        */
+/*     $OpenBSD: sshbuf-misc.c,v 1.21 2025/07/24 05:44:55 djm Exp $    */
 /*
  * Copyright (c) 2011 Damien Miller
  *
@@ -285,6 +285,20 @@ sshbuf_cmp(const struct sshbuf *b, size_t offset,
        return 0;
 }
 
+int
+sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b)
+{
+       if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL)
+               return SSH_ERR_INTERNAL_ERROR;
+       if (sshbuf_len(a) != sshbuf_len(b))
+               return SSH_ERR_MESSAGE_INCOMPLETE;
+       if (sshbuf_len(a) == 0)
+               return 0;
+       if (memcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0)
+               return SSH_ERR_INVALID_FORMAT;
+       return 0;
+}
+
 int
 sshbuf_find(const struct sshbuf *b, size_t start_offset,
     const void *s, size_t len, size_t *offsetp)
index 681abb9eec03e0face34c023d00be4f39352b333..f0cc4c5f8e38122574b1b39c6f8e697ab24cf703 100644 (file)
--- a/sshbuf.h
+++ b/sshbuf.h
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sshbuf.h,v 1.30 2025/05/21 06:43:48 djm Exp $ */
+/*     $OpenBSD: sshbuf.h,v 1.31 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2011 Damien Miller
  *
@@ -263,6 +263,15 @@ int        sshbuf_b64tod(struct sshbuf *buf, const char *b64);
 int    sshbuf_cmp(const struct sshbuf *b, size_t offset,
     const void *s, size_t len);
 
+/*
+ * Test whether two buffers have identical contents.
+ * SSH_ERR_MESSAGE_INCOMPLETE indicates the buffers had differing size.
+ * SSH_ERR_INVALID_FORMAT indicates the buffers were the same size but
+ * had differing contents.
+ * Returns 0 on successful compare (comparing two empty buffers returns 0).
+ */
+int sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b);
+
 /*
  * Searches the buffer for the specified string. Returns 0 on success
  * and updates *offsetp with the offset of the first match, relative to
index 9e31411e21d6d84116e5c7a41e762b26b7f28838..3b1335d997252fdfcafd5e18be1407ebd1efc682 100644 (file)
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.150 2025/05/12 05:41:20 tb Exp $ */
+/* $OpenBSD: sshkey.c,v 1.151 2025/07/24 05:44:55 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -60,6 +60,7 @@
 #include "sshkey.h"
 #include "match.h"
 #include "ssh-sk.h"
+#include "ssh-pkcs11.h"
 
 #ifdef WITH_XMSS
 #include "sshkey-xmss.h"
@@ -778,6 +779,8 @@ sshkey_free_contents(struct sshkey *k)
 
        if (k == NULL)
                return;
+       if ((k->flags & SSHKEY_FLAG_EXT) != 0)
+               pkcs11_key_free(k);
        if ((impl = sshkey_impl_from_type(k->type)) != NULL &&
            impl->funcs->cleanup != NULL)
                impl->funcs->cleanup(k);
@@ -900,22 +903,29 @@ sshkey_putb(const struct sshkey *key, struct sshbuf *b)
        return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
 }
 
-int
-sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
-    enum sshkey_serialize_rep opts)
+static int
+sshkey_puts_opts_internal(const struct sshkey *key, struct sshbuf *b,
+    enum sshkey_serialize_rep opts, int force_plain)
 {
        struct sshbuf *tmp;
        int r;
 
        if ((tmp = sshbuf_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
-       r = to_blob_buf(key, tmp, 0, opts);
+       r = to_blob_buf(key, tmp, force_plain, opts);
        if (r == 0)
                r = sshbuf_put_stringb(b, tmp);
        sshbuf_free(tmp);
        return r;
 }
 
+int
+sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
+    enum sshkey_serialize_rep opts)
+{
+       return sshkey_puts_opts_internal(key, b, opts, 0);
+}
+
 int
 sshkey_puts(const struct sshkey *key, struct sshbuf *b)
 {
@@ -928,6 +938,12 @@ sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
        return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
 }
 
+int
+sshkey_puts_plain(const struct sshkey *key, struct sshbuf *b)
+{
+       return sshkey_puts_opts_internal(key, b, SSHKEY_SERIALIZE_DEFAULT, 1);
+}
+
 static int
 to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
     enum sshkey_serialize_rep opts)
@@ -2200,6 +2216,9 @@ sshkey_sign(struct sshkey *key,
        if (sshkey_is_sk(key)) {
                r = sshsk_sign(sk_provider, key, sigp, lenp, data,
                    datalen, compat, sk_pin);
+       } else if ((key->flags & SSHKEY_FLAG_EXT) != 0) {
+               r = pkcs11_sign(key, sigp, lenp, data, datalen,
+                   alg, sk_provider, sk_pin, compat);
        } else {
                if (impl->funcs->sign == NULL)
                        r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
index 5fa410b9431d2fc1b863066486fc8c53387d7993..13309416b6c80fc1a94fb3f187520b1c788afb35 100644 (file)
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.67 2025/05/06 05:40:56 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.68 2025/07/24 05:44:55 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -275,6 +275,7 @@ int  sshkey_puts_opts(const struct sshkey *, struct sshbuf *,
     enum sshkey_serialize_rep);
 int     sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
 int     sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
+int     sshkey_puts_plain(const struct sshkey *, struct sshbuf *);
 
 int     sshkey_sign(struct sshkey *, u_char **, size_t *,
     const u_char *, size_t, const char *, const char *, const char *, u_int);
@@ -312,6 +313,12 @@ int        sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
     int type, struct sshkey **pubkeyp);
 
 int sshkey_check_rsa_length(const struct sshkey *, int);
+int    ssh_rsa_hash_id_from_keyname(const char *);
+const char *ssh_rsa_hash_alg_ident(int);
+int    ssh_rsa_encode_store_sig(int, const u_char *, size_t,
+           u_char **, size_t *);
+int    ssh_ecdsa_encode_store_sig(const struct sshkey *,
+           const BIGNUM *, const BIGNUM *, u_char **, size_t *);
 /* XXX should be internal, but used by ssh-keygen */
 int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *,
     const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **);