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
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
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 \
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 \
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 \
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
-/* $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.
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;
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;
*lenp = len;
ret = 0;
out:
- freezero(sigb, slen);
sshbuf_free(b);
sshbuf_free(bb);
- ECDSA_SIG_free(esig);
return ret;
}
-/* $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.
#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;
}
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) {
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)
{
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;
}
/*
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)) {
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)
{
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) {
{
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;
(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 ||
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
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);
+}
-/* $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.
*
# 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*/
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)
{
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 ||
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:
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);
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();
_exit(i);
}
-
int
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);
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)
{
-/* $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"
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)
{
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.
}
}
-/* 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)
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);
}
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 *
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)
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;
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) {
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");
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)
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,
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;
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");
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
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;
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");
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");
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");
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;
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;
}
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,
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) {
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
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,
-/* $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,
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
-/* $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>
*
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:
* 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;
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;
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)
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;
*lenp = len;
ret = 0;
out:
- freezero(sig, slen);
sshbuf_free(b);
return ret;
}
* 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;
}
-/* $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
*
#include "uidswap.h"
#include "ssherr.h"
#include "ssh-sk.h"
+#include "ssh-pkcs11.h"
#ifdef ENABLE_SK
extern char *__progname;
*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)
{
-/* $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
*
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)
-/* $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
*
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
-/* $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.
#include "sshkey.h"
#include "match.h"
#include "ssh-sk.h"
+#include "ssh-pkcs11.h"
#ifdef WITH_XMSS
#include "sshkey-xmss.h"
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);
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)
{
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)
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;
-/* $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.
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);
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 **);