diff --git a/.depend b/.depend index f569b603d..365db15a8 100644 --- a/.depend +++ b/.depend @@ -145,7 +145,6 @@ ssh-rsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compa 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-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 ssh.o: sshkey.h authfd.h authfile.h pathnames.h clientloop.h log.h ssherr.h misc.h readconf.h sshconnect.h kex.h mac.h crypto_api.h sshpty.h match.h msg.h version.h myproposal.h utf8.h ssh_api.o: authfile.h dh.h misc.h version.h myproposal.h sshbuf.h openbsd-compat/openssl-compat.h @@ -166,7 +165,6 @@ sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd- 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 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 @@ -178,8 +176,3 @@ umac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h umac128.o: umac.c 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 umac.h misc.h rijndael.h utf8.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 utf8.h xmalloc.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 -xmss_commons.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 -xmss_fast.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 -xmss_hash.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 -xmss_hash_address.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 -xmss_wots.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 diff --git a/Makefile.in b/Makefile.in index 9e45d5220..19a9e4dcf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -76,15 +76,6 @@ MKDIR_P=@MKDIR_P@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) sshd-auth$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) $(SK_STANDALONE) -XMSS_OBJS=\ - ssh-xmss.o \ - sshkey-xmss.o \ - xmss_commons.o \ - xmss_fast.o \ - xmss_hash.o \ - xmss_hash_address.o \ - xmss_wots.o - LIBOPENSSH_OBJS=\ ssh_api.o \ ssherr.o \ @@ -94,8 +85,7 @@ LIBOPENSSH_OBJS=\ sshbuf-misc.o \ sshbuf-getput-crypto.o \ krl.o \ - bitmap.o \ - ${XMSS_OBJS} + bitmap.o LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ authfd.o authfile.o \ diff --git a/PROTOCOL.agent b/PROTOCOL.agent index b6e14262d..2af749b30 100644 --- a/PROTOCOL.agent +++ b/PROTOCOL.agent @@ -73,17 +73,6 @@ identities and, in particular, signature requests will check the key constraints against the session-bind@openssh.com bindings recorded for the agent connection over which they were received. -3. SSH_AGENT_CONSTRAIN_MAXSIGN key constraint - -This key constraint allows communication to an agent of the maximum -number of signatures that may be made with an XMSS key. The format of -the constraint is: - - byte SSH_AGENT_CONSTRAIN_MAXSIGN (0x03) - uint32 max_signatures - -This option is only valid for XMSS keys. - 3. associated-certs-v00@openssh.com key constraint extension The key constraint extension allows certificates to be associated @@ -115,4 +104,4 @@ A SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED will return SSH_AGENT_SUCCESS if any key (plain private or certificate) was successfully loaded, or SSH_AGENT_FAILURE if no key was loaded. -$OpenBSD: PROTOCOL.agent,v 1.24 2024/11/27 13:27:34 djm Exp $ +$OpenBSD: PROTOCOL.agent,v 1.25 2025/08/29 03:50:38 djm Exp $ diff --git a/authfd.c b/authfd.c index 66797880a..2bbe646e3 100644 --- a/authfd.c +++ b/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.135 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: authfd.c,v 1.136 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -505,7 +505,7 @@ encode_dest_constraint(struct sshbuf *m, const struct dest_constraint *dc) static int encode_constraints(struct sshbuf *m, u_int life, u_int confirm, - u_int maxsign, const char *provider, + const char *provider, struct dest_constraint **dest_constraints, size_t ndest_constraints, int cert_only, struct sshkey **certs, size_t ncerts) { @@ -522,11 +522,6 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) goto out; } - if (maxsign != 0) { - if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 || - (r = sshbuf_put_u32(m, maxsign)) != 0) - goto out; - } if (provider != NULL) { if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 || @@ -585,13 +580,12 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, */ int ssh_add_identity_constrained(int sock, struct sshkey *key, - const char *comment, u_int life, u_int confirm, u_int maxsign, + const char *comment, u_int life, u_int confirm, const char *provider, struct dest_constraint **dest_constraints, size_t ndest_constraints) { struct sshbuf *msg; - int r, constrained = (life || confirm || maxsign || - provider || dest_constraints); + int r, constrained = (life || confirm || provider || dest_constraints); u_char type; if ((msg = sshbuf_new()) == NULL) @@ -610,14 +604,11 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, case KEY_ED25519_CERT: case KEY_ED25519_SK: case KEY_ED25519_SK_CERT: - case KEY_XMSS: - case KEY_XMSS_CERT: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; if ((r = sshbuf_put_u8(msg, type)) != 0 || - (r = sshkey_private_serialize_maxsign(key, msg, maxsign, - 0)) != 0 || + (r = sshkey_private_serialize(key, msg)) != 0 || (r = sshbuf_put_cstring(msg, comment)) != 0) goto out; break; @@ -626,8 +617,8 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, goto out; } if (constrained && - (r = encode_constraints(msg, life, confirm, maxsign, - provider, dest_constraints, ndest_constraints, 0, NULL, 0)) != 0) + (r = encode_constraints(msg, life, confirm, provider, + dest_constraints, ndest_constraints, 0, NULL, 0)) != 0) goto out; if ((r = ssh_request_reply_decode(sock, msg)) != 0) goto out; @@ -703,7 +694,7 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin, (r = sshbuf_put_cstring(msg, pin)) != 0) goto out; if (constrained && - (r = encode_constraints(msg, life, confirm, 0, NULL, + (r = encode_constraints(msg, life, confirm, NULL, dest_constraints, ndest_constraints, cert_only, certs, ncerts)) != 0) goto out; diff --git a/authfd.h b/authfd.h index c1e4b405c..958d480de 100644 --- a/authfd.h +++ b/authfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.h,v 1.52 2023/12/18 14:46:56 djm Exp $ */ +/* $OpenBSD: authfd.h,v 1.53 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -48,9 +48,8 @@ int ssh_lock_agent(int sock, int lock, const char *password); int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp); void ssh_free_identitylist(struct ssh_identitylist *idl); int ssh_add_identity_constrained(int sock, struct sshkey *key, - const char *comment, u_int life, u_int confirm, u_int maxsign, - const char *provider, struct dest_constraint **dest_constraints, - size_t ndest_constraints); + const char *comment, u_int life, u_int confirm, const char *provider, + struct dest_constraint **dest_constraints, size_t ndest_constraints); int ssh_agent_has_key(int sock, const struct sshkey *key); int ssh_remove_identity(int sock, const struct sshkey *key); int ssh_update_card(int sock, int add, const char *reader_id, @@ -106,7 +105,6 @@ int ssh_agent_bind_hostkey(int sock, const struct sshkey *key, #define SSH_AGENT_CONSTRAIN_LIFETIME 1 #define SSH_AGENT_CONSTRAIN_CONFIRM 2 -#define SSH_AGENT_CONSTRAIN_MAXSIGN 3 #define SSH_AGENT_CONSTRAIN_EXTENSION 255 /* extended failure messages */ diff --git a/authfile.c b/authfile.c index bf485baf2..16e02d9d0 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.146 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.147 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. * @@ -131,8 +131,6 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase, goto out; r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp); - if (r == 0 && keyp && *keyp) - r = sshkey_set_filename(*keyp, filename); out: close(fd); return r; @@ -184,8 +182,6 @@ sshkey_load_pubkey_from_private(const char *filename, struct sshkey **pubkeyp) (r = sshkey_parse_pubkey_from_private_fileblob_type(buffer, KEY_UNSPEC, &pubkey)) != 0) goto out; - if ((r = sshkey_set_filename(pubkey, filename)) != 0) - goto out; /* success */ if (pubkeyp != NULL) { *pubkeyp = pubkey; @@ -331,7 +327,6 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase, case KEY_ECDSA: #endif /* WITH_OPENSSL */ case KEY_ED25519: - case KEY_XMSS: case KEY_UNSPEC: break; default: diff --git a/dns.c b/dns.c index c01c7bebe..e8693cee8 100644 --- a/dns.c +++ b/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.45 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: dns.c,v 1.46 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -94,9 +94,6 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, case KEY_ED25519: *algorithm = SSHFP_KEY_ED25519; break; - case KEY_XMSS: - *algorithm = SSHFP_KEY_XMSS; - break; default: *algorithm = SSHFP_KEY_RESERVED; /* 0 */ } diff --git a/dns.h b/dns.h index 864ab7d00..ab2df061e 100644 --- a/dns.h +++ b/dns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.h,v 1.20 2023/02/10 04:56:30 djm Exp $ */ +/* $OpenBSD: dns.h,v 1.21 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -33,8 +33,7 @@ enum sshfp_types { SSHFP_KEY_RSA = 1, SSHFP_KEY_DSA = 2, SSHFP_KEY_ECDSA = 3, - SSHFP_KEY_ED25519 = 4, - SSHFP_KEY_XMSS = 5 + SSHFP_KEY_ED25519 = 4 }; enum sshfp_hashes { diff --git a/pathnames.h b/pathnames.h index 9e76dbba8..0dcc49552 100644 --- a/pathnames.h +++ b/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.35 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: pathnames.h,v 1.36 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -38,7 +38,6 @@ #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" #define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" -#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" #define _PATH_DH_MODULI SSHDIR "/moduli" @@ -89,7 +88,6 @@ #define _PATH_SSH_CLIENT_ID_ECDSA _PATH_SSH_USER_DIR "/id_ecdsa" #define _PATH_SSH_CLIENT_ID_RSA _PATH_SSH_USER_DIR "/id_rsa" #define _PATH_SSH_CLIENT_ID_ED25519 _PATH_SSH_USER_DIR "/id_ed25519" -#define _PATH_SSH_CLIENT_ID_XMSS _PATH_SSH_USER_DIR "/id_xmss" #define _PATH_SSH_CLIENT_ID_ECDSA_SK _PATH_SSH_USER_DIR "/id_ecdsa_sk" #define _PATH_SSH_CLIENT_ID_ED25519_SK _PATH_SSH_USER_DIR "/id_ed25519_sk" diff --git a/readconf.c b/readconf.c index c7701d8c2..ba25ba881 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.405 2025/08/11 10:55:38 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.406 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2911,7 +2911,6 @@ fill_default_options(Options * options) _PATH_SSH_CLIENT_ID_ED25519, 0); add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ED25519_SK, 0); - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); } if (options->escape_char == -1) options->escape_char = '~'; diff --git a/servconf.c b/servconf.c index 92f924e60..3175f0df8 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.430 2025/08/05 09:08:16 job Exp $ */ +/* $OpenBSD: servconf.c,v 1.431 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -314,10 +314,6 @@ fill_default_server_options(ServerOptions *options) #endif servconf_add_hostkey("[default]", 0, options, _PATH_HOST_ED25519_KEY_FILE, 0); -#ifdef WITH_XMSS - servconf_add_hostkey("[default]", 0, options, - _PATH_HOST_XMSS_KEY_FILE, 0); -#endif /* WITH_XMSS */ } /* No certificates by default */ if (options->num_ports == 0) diff --git a/ssh-add.c b/ssh-add.c index 18897a0a8..2e41bc26a 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.174 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.175 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -84,7 +84,6 @@ static char *default_files[] = { #endif /* WITH_OPENSSL */ _PATH_SSH_CLIENT_ID_ED25519, _PATH_SSH_CLIENT_ID_ED25519_SK, - _PATH_SSH_CLIENT_ID_XMSS, NULL }; @@ -96,10 +95,6 @@ static int lifetime = 0; /* User has to confirm key use */ static int confirm = 0; -/* Maximum number of signatures (XMSS) */ -static u_int maxsign = 0; -static u_int minleft = 0; - /* we keep a cache of one passphrase */ static char *pass = NULL; static void @@ -249,10 +244,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, char *comment = NULL; char msg[1024], *certpath = NULL; int r, fd, ret = -1; - size_t i; - u_int32_t left; struct sshbuf *keyblob; - struct ssh_identitylist *idlist; if (strcmp(filename, "-") == 0) { fd = STDIN_FILENO; @@ -328,38 +320,6 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, comment = xstrdup(filename); sshbuf_free(keyblob); - /* For XMSS */ - if ((r = sshkey_set_filename(private, filename)) != 0) { - fprintf(stderr, "Could not add filename to private key: %s (%s)\n", - filename, comment); - goto out; - } - if (maxsign && minleft && - (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { - for (i = 0; i < idlist->nkeys; i++) { - if (!sshkey_equal_public(idlist->keys[i], private)) - continue; - left = sshkey_signatures_left(idlist->keys[i]); - if (left < minleft) { - fprintf(stderr, - "Only %d signatures left.\n", left); - break; - } - fprintf(stderr, "Skipping update: "); - if (left == minleft) { - fprintf(stderr, - "required signatures left (%d).\n", left); - } else { - fprintf(stderr, - "more signatures left (%d) than" - " required (%d).\n", left, minleft); - } - ssh_free_identitylist(idlist); - goto out; - } - ssh_free_identitylist(idlist); - } - if (sshkey_is_sk(private)) { if (skprovider == NULL) { fprintf(stderr, "Cannot load FIDO key %s " @@ -373,7 +333,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, if (!cert_only && (r = ssh_add_identity_constrained(agent_fd, private, comment, - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) == 0) { ret = 0; if (!qflag) { @@ -427,7 +387,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, sshkey_free(cert); if ((r = ssh_add_identity_constrained(agent_fd, private, comment, - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) != 0) { error_r(r, "Certificate %s (%s) add failed", certpath, private->cert->key_id); @@ -531,7 +491,6 @@ list_identities(int agent_fd, int do_fp) char *fp; int r; struct ssh_identitylist *idlist; - u_int32_t left; size_t i; if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { @@ -556,12 +515,7 @@ list_identities(int agent_fd, int do_fp) ssh_err(r)); continue; } - fprintf(stdout, " %s", idlist->comments[i]); - left = sshkey_signatures_left(idlist->keys[i]); - if (left > 0) - fprintf(stdout, - " [signatures left %d]", left); - fprintf(stdout, "\n"); + fprintf(stdout, " %s\n", idlist->comments[i]); } } ssh_free_identitylist(idlist); @@ -620,7 +574,7 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag, fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal_f("sshkey_fingerprint failed"); if ((r = ssh_add_identity_constrained(agent_fd, key, "", - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) != 0) { error("Unable to add key %s %s", sshkey_type(key), fp); @@ -791,9 +745,6 @@ usage(void) fprintf(stderr, "usage: ssh-add [-CcDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n" " [-h destination_constraint] [-S provider] [-t life]\n" -#ifdef WITH_XMSS -" [-M maxsign] [-m minleft]\n" -#endif " [file ...]\n" " ssh-add -s pkcs11 [-Cv] [certificate ...]\n" " ssh-add -e pkcs11\n" @@ -887,20 +838,8 @@ main(int argc, char **argv) confirm = 1; break; case 'm': - minleft = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); - if (minleft == 0) { - usage(); - ret = 1; - goto done; - } - break; case 'M': - maxsign = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); - if (maxsign == 0) { - usage(); - ret = 1; - goto done; - } + /* deprecated */ break; case 'd': deleting = 1; diff --git a/ssh-agent.c b/ssh-agent.c index d82b351d0..2c7b94be5 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.312 2025/05/05 02:48:06 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.313 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -644,8 +644,7 @@ process_request_identities(SocketEntry *e) /* identity not visible, don't include in response */ if (identity_permitted(id, e, NULL, NULL, NULL) != 0) continue; - if ((r = sshkey_puts_opts(id->key, keys, - SSHKEY_SERIALIZE_INFO)) != 0 || + if ((r = sshkey_puts(id->key, keys)) != 0 || (r = sshbuf_put_cstring(keys, id->comment)) != 0) { error_fr(r, "compose key/comment"); continue; @@ -1292,7 +1291,7 @@ parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp, { u_char ctype; int r; - u_int seconds, maxsign = 0; + u_int seconds; while (sshbuf_len(m)) { if ((r = sshbuf_get_u8(m, &ctype)) != 0) { @@ -1321,26 +1320,6 @@ parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp, } *confirmp = 1; break; - case SSH_AGENT_CONSTRAIN_MAXSIGN: - if (k == NULL) { - error_f("maxsign not valid here"); - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (maxsign != 0) { - error_f("maxsign already set"); - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if ((r = sshbuf_get_u32(m, &maxsign)) != 0) { - error_fr(r, "parse maxsign constraint"); - goto out; - } - if ((r = sshkey_enable_maxsign(k, maxsign)) != 0) { - error_fr(r, "enable maxsign"); - goto out; - } - break; case SSH_AGENT_CONSTRAIN_EXTENSION: if ((r = parse_key_constraint_extension(m, sk_providerp, dcsp, ndcsp, diff --git a/ssh-keygen.c b/ssh-keygen.c index 867fbd1ca..6e6288637 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.481 2025/05/24 03:37:40 dtucker Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.482 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -273,10 +273,6 @@ ask_filename(struct passwd *pw, const char *prompt) case KEY_ED25519_SK_CERT: name = _PATH_SSH_CLIENT_ID_ED25519_SK; break; - case KEY_XMSS: - case KEY_XMSS_CERT: - name = _PATH_SSH_CLIENT_ID_XMSS; - break; default: fatal("bad key type"); } @@ -1024,9 +1020,6 @@ do_gen_all_hostkeys(struct passwd *pw) #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, -#ifdef WITH_XMSS - { "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE }, -#endif /* WITH_XMSS */ { NULL, NULL, NULL } }; @@ -1521,7 +1514,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment) } } - if (private->type != KEY_ED25519 && private->type != KEY_XMSS && + if (private->type != KEY_ED25519 && private_key_format != SSHKEY_PRIVATE_OPENSSH) { error("Comments are only supported for keys stored in " "the new format (-o)."); @@ -3727,9 +3720,6 @@ main(int argc, char **argv) n += do_print_resource_record(pw, _PATH_HOST_ED25519_KEY_FILE, rr_hostname, print_generic, opts, nopts); - n += do_print_resource_record(pw, - _PATH_HOST_XMSS_KEY_FILE, rr_hostname, - print_generic, opts, nopts); if (n == 0) fatal("no keys found."); exit(0); diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 7b1e0ca86..914de1244 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.166 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.167 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -65,7 +65,6 @@ int ssh_port = SSH_DEFAULT_PORT; #define KT_RSA (1) #define KT_ECDSA (1<<1) #define KT_ED25519 (1<<2) -#define KT_XMSS (1<<3) #define KT_ECDSA_SK (1<<4) #define KT_ED25519_SK (1<<5) @@ -252,10 +251,6 @@ keygrab_ssh2(con *c) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519"; break; - case KT_XMSS: - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? - "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com"; - break; case KT_ECDSA: myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? "ecdsa-sha2-nistp256-cert-v01@openssh.com," @@ -747,9 +742,6 @@ main(int argc, char **argv) case KEY_ED25519: get_keytypes |= KT_ED25519; break; - case KEY_XMSS: - get_keytypes |= KT_XMSS; - break; case KEY_ED25519_SK: get_keytypes |= KT_ED25519_SK; break; diff --git a/ssh-keysign.c b/ssh-keysign.c index 4d65dd1d3..2410c6cd1 100644 --- a/ssh-keysign.c +++ b/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.76 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.77 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -202,7 +202,6 @@ main(int argc, char **argv) /* XXX This really needs to read sshd_config for the paths */ key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY); - key_fd[i++] = open(_PATH_HOST_XMSS_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY); if ((pw = getpwuid(getuid())) == NULL) diff --git a/ssh-xmss.c b/ssh-xmss.c deleted file mode 100644 index b6d0561b1..000000000 --- a/ssh-xmss.c +++ /dev/null @@ -1,389 +0,0 @@ -/* $OpenBSD: ssh-xmss.c,v 1.14 2022/10/28 00:44:44 djm Exp $*/ -/* - * Copyright (c) 2017 Stefan-Lukas Gazdag. - * Copyright (c) 2017 Markus Friedl. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include "includes.h" -#ifdef WITH_XMSS - -#define SSHKEY_INTERNAL -#include -#include - -#include -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include - -#include "log.h" -#include "sshbuf.h" -#include "sshkey.h" -#include "sshkey-xmss.h" -#include "ssherr.h" -#include "ssh.h" - -#include "xmss_fast.h" - -static void -ssh_xmss_cleanup(struct sshkey *k) -{ - freezero(k->xmss_pk, sshkey_xmss_pklen(k)); - freezero(k->xmss_sk, sshkey_xmss_sklen(k)); - sshkey_xmss_free_state(k); - free(k->xmss_name); - free(k->xmss_filename); - k->xmss_pk = NULL; - k->xmss_sk = NULL; - k->xmss_name = NULL; - k->xmss_filename = NULL; -} - -static int -ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b) -{ - if (a->xmss_pk == NULL || b->xmss_pk == NULL) - return 0; - if (sshkey_xmss_pklen(a) != sshkey_xmss_pklen(b)) - return 0; - if (memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) != 0) - return 0; - return 1; -} - -static int -ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - - if (key->xmss_name == NULL || key->xmss_pk == NULL || - sshkey_xmss_pklen(key) == 0) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || - (r = sshbuf_put_string(b, key->xmss_pk, - sshkey_xmss_pklen(key))) != 0 || - (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0) - return r; - - return 0; -} - -static int -ssh_xmss_serialize_private(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - - if (key->xmss_name == NULL) - return SSH_ERR_INVALID_ARGUMENT; - /* Note: can't reuse ssh_xmss_serialize_public because of sk order */ - if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || - (r = sshbuf_put_string(b, key->xmss_pk, - sshkey_xmss_pklen(key))) != 0 || - (r = sshbuf_put_string(b, key->xmss_sk, - sshkey_xmss_sklen(key))) != 0 || - (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0) - return r; - - return 0; -} - -static int -ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to) -{ - int r = SSH_ERR_INTERNAL_ERROR; - u_int32_t left; - size_t pklen; - - if ((r = sshkey_xmss_init(to, from->xmss_name)) != 0) - return r; - if (from->xmss_pk == NULL) - return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */ - - if ((pklen = sshkey_xmss_pklen(from)) == 0 || - sshkey_xmss_pklen(to) != pklen) - return SSH_ERR_INTERNAL_ERROR; - if ((to->xmss_pk = malloc(pklen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - memcpy(to->xmss_pk, from->xmss_pk, pklen); - /* simulate number of signatures left on pubkey */ - left = sshkey_xmss_signatures_left(from); - if (left) - sshkey_xmss_enable_maxsign(to, left); - return 0; -} - -static int -ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - size_t len = 0; - char *xmss_name = NULL; - u_char *pk = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - - if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0) - goto out; - if ((ret = sshkey_xmss_init(key, xmss_name)) != 0) - goto out; - if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) - goto out; - if (len == 0 || len != sshkey_xmss_pklen(key)) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } - key->xmss_pk = pk; - pk = NULL; - if (!sshkey_is_cert(key) && - (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0) - goto out; - /* success */ - ret = 0; - out: - free(xmss_name); - freezero(pk, len); - return ret; -} - -static int -ssh_xmss_deserialize_private(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - int r; - char *xmss_name = NULL; - size_t pklen = 0, sklen = 0; - u_char *xmss_pk = NULL, *xmss_sk = NULL; - - /* Note: can't reuse ssh_xmss_deserialize_public because of sk order */ - if ((r = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0 || - (r = sshbuf_get_string(b, &xmss_pk, &pklen)) != 0 || - (r = sshbuf_get_string(b, &xmss_sk, &sklen)) != 0) - goto out; - if (!sshkey_is_cert(key) && - (r = sshkey_xmss_init(key, xmss_name)) != 0) - goto out; - if (pklen != sshkey_xmss_pklen(key) || - sklen != sshkey_xmss_sklen(key)) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - key->xmss_pk = xmss_pk; - key->xmss_sk = xmss_sk; - xmss_pk = xmss_sk = NULL; - /* optional internal state */ - if ((r = sshkey_xmss_deserialize_state_opt(key, b)) != 0) - goto out; - /* success */ - r = 0; - out: - free(xmss_name); - freezero(xmss_pk, pklen); - freezero(xmss_sk, sklen); - return r; -} - -static int -ssh_xmss_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) -{ - u_char *sig = NULL; - size_t slen = 0, len = 0, required_siglen; - unsigned long long smlen; - int r, ret; - struct sshbuf *b = NULL; - - if (lenp != NULL) - *lenp = 0; - if (sigp != NULL) - *sigp = NULL; - - if (key == NULL || - sshkey_type_plain(key->type) != KEY_XMSS || - key->xmss_sk == NULL || - sshkey_xmss_params(key) == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) - return r; - if (datalen >= INT_MAX - required_siglen) - return SSH_ERR_INVALID_ARGUMENT; - smlen = slen = datalen + required_siglen; - if ((sig = malloc(slen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshkey_xmss_get_state(key, 1)) != 0) - goto out; - if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen, - data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) { - r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ - goto out; - } - /* encode signature */ - if ((b = sshbuf_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 || - (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) - goto out; - len = sshbuf_len(b); - if (sigp != NULL) { - if ((*sigp = malloc(len)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - memcpy(*sigp, sshbuf_ptr(b), len); - } - if (lenp != NULL) - *lenp = len; - /* success */ - r = 0; - out: - if ((ret = sshkey_xmss_update_state(key, 1)) != 0) { - /* discard signature since we cannot update the state */ - if (r == 0 && sigp != NULL && *sigp != NULL) { - explicit_bzero(*sigp, len); - free(*sigp); - } - if (sigp != NULL) - *sigp = NULL; - if (lenp != NULL) - *lenp = 0; - r = ret; - } - sshbuf_free(b); - if (sig != NULL) - freezero(sig, slen); - - return r; -} - -static int -ssh_xmss_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) -{ - struct sshbuf *b = NULL; - char *ktype = NULL; - const u_char *sigblob; - u_char *sm = NULL, *m = NULL; - size_t len, required_siglen; - unsigned long long smlen = 0, mlen = 0; - int r, ret; - - if (key == NULL || - sshkey_type_plain(key->type) != KEY_XMSS || - key->xmss_pk == NULL || - sshkey_xmss_params(key) == NULL || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) - return r; - if (dlen >= INT_MAX - required_siglen) - return SSH_ERR_INVALID_ARGUMENT; - - if ((b = sshbuf_from(sig, siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || - (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) - goto out; - if (strcmp("ssh-xmss@openssh.com", ktype) != 0) { - r = SSH_ERR_KEY_TYPE_MISMATCH; - goto out; - } - if (sshbuf_len(b) != 0) { - r = SSH_ERR_UNEXPECTED_TRAILING_DATA; - goto out; - } - if (len != required_siglen) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (dlen >= SIZE_MAX - len) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - smlen = len + dlen; - mlen = smlen; - if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - memcpy(sm, sigblob, len); - memcpy(sm+len, data, dlen); - if ((ret = xmss_sign_open(m, &mlen, sm, smlen, - key->xmss_pk, sshkey_xmss_params(key))) != 0) { - debug2_f("xmss_sign_open failed: %d", ret); - } - if (ret != 0 || mlen != dlen) { - r = SSH_ERR_SIGNATURE_INVALID; - goto out; - } - /* XXX compare 'm' and 'data' ? */ - /* success */ - r = 0; - out: - if (sm != NULL) - freezero(sm, smlen); - if (m != NULL) - freezero(m, smlen); - sshbuf_free(b); - free(ktype); - return r; -} - -static const struct sshkey_impl_funcs sshkey_xmss_funcs = { - /* .size = */ NULL, - /* .alloc = */ NULL, - /* .cleanup = */ ssh_xmss_cleanup, - /* .equal = */ ssh_xmss_equal, - /* .ssh_serialize_public = */ ssh_xmss_serialize_public, - /* .ssh_deserialize_public = */ ssh_xmss_deserialize_public, - /* .ssh_serialize_private = */ ssh_xmss_serialize_private, - /* .ssh_deserialize_private = */ ssh_xmss_deserialize_private, - /* .generate = */ sshkey_xmss_generate_private_key, - /* .copy_public = */ ssh_xmss_copy_public, - /* .sign = */ ssh_xmss_sign, - /* .verify = */ ssh_xmss_verify, -}; - -const struct sshkey_impl sshkey_xmss_impl = { - /* .name = */ "ssh-xmss@openssh.com", - /* .shortname = */ "XMSS", - /* .sigalg = */ NULL, - /* .type = */ KEY_XMSS, - /* .nid = */ 0, - /* .cert = */ 0, - /* .sigonly = */ 0, - /* .keybits = */ 256, - /* .funcs = */ &sshkey_xmss_funcs, -}; - -const struct sshkey_impl sshkey_xmss_cert_impl = { - /* .name = */ "ssh-xmss-cert-v01@openssh.com", - /* .shortname = */ "XMSS-CERT", - /* .sigalg = */ NULL, - /* .type = */ KEY_XMSS_CERT, - /* .nid = */ 0, - /* .cert = */ 1, - /* .sigonly = */ 0, - /* .keybits = */ 256, - /* .funcs = */ &sshkey_xmss_funcs, -}; -#endif /* WITH_XMSS */ diff --git a/ssh.c b/ssh.c index 58c254b93..1eaa5986e 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.615 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.616 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1762,8 +1762,6 @@ main(int ac, char **av) L_PUBKEY(_PATH_HOST_ECDSA_KEY_FILE, 4); L_PUBKEY(_PATH_HOST_ED25519_KEY_FILE, 5); L_PUBKEY(_PATH_HOST_RSA_KEY_FILE, 6); - L_CERT(_PATH_HOST_XMSS_KEY_FILE, 8); - L_PUBKEY(_PATH_HOST_XMSS_KEY_FILE, 9); if (loaded == 0) debug("HostbasedAuthentication enabled but no " "local public host keys could be loaded."); diff --git a/sshconnect.c b/sshconnect.c index d2c8cf0bd..8ddc531da 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.373 2025/08/12 11:09:48 sthen Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.374 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1640,7 +1640,6 @@ show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) KEY_RSA, KEY_ECDSA, KEY_ED25519, - KEY_XMSS, -1 }; int i, ret = 0; @@ -1763,7 +1762,7 @@ maybe_add_key_to_agent(const char *authfile, struct sshkey *private, if ((r = ssh_add_identity_constrained(auth_sock, private, comment == NULL ? authfile : comment, options.add_keys_to_agent_lifespan, - (options.add_keys_to_agent == 3), 0, skprovider, NULL, 0)) == 0) + (options.add_keys_to_agent == 3), skprovider, NULL, 0)) == 0) debug("identity added to agent: %s", authfile); else debug("could not add identity to agent: %s (%d)", authfile, r); diff --git a/sshd-auth.c b/sshd-auth.c index 6bb4aff0d..95520608c 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.7 2025/08/18 04:38:21 djm Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.8 2025/08/29 03:50:38 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -254,7 +254,6 @@ list_hostkey_types(void) case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: - case KEY_XMSS: append_hostkey_type(b, sshkey_ssh_name(key)); break; } @@ -274,7 +273,6 @@ list_hostkey_types(void) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: append_hostkey_type(b, sshkey_ssh_name(key)); break; } @@ -299,7 +297,6 @@ get_hostkey_public_by_type(int type, int nid, struct ssh *ssh) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: key = host_certificates[i]; break; default: diff --git a/sshd-session.c b/sshd-session.c index 4aad8b6fe..5c0075630 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.14 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.15 2025/08/29 03:50:38 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -489,7 +489,6 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: key = sensitive_data.host_certificates[i]; break; default: diff --git a/sshd.c b/sshd.c index 696019381..f77a4a2ec 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.621 2025/07/04 09:51:01 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.622 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -1672,7 +1672,6 @@ main(int ac, char **av) case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: - case KEY_XMSS: if (have_agent || key != NULL) sensitive_data.have_ssh2_key = 1; break; diff --git a/sshkey-xmss.c b/sshkey-xmss.c deleted file mode 100644 index 818aba905..000000000 --- a/sshkey-xmss.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* $OpenBSD: sshkey-xmss.c,v 1.12 2022/10/28 00:39:29 djm Exp $ */ -/* - * Copyright (c) 2017 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_FILE_H -# include -#endif - -#include "ssh2.h" -#include "ssherr.h" -#include "sshbuf.h" -#include "cipher.h" -#include "sshkey.h" -#include "sshkey-xmss.h" -#include "atomicio.h" -#include "log.h" - -#include "xmss_fast.h" - -/* opaque internal XMSS state */ -#define XMSS_MAGIC "xmss-state-v1" -#define XMSS_CIPHERNAME "aes256-gcm@openssh.com" -struct ssh_xmss_state { - xmss_params params; - u_int32_t n, w, h, k; - - bds_state bds; - u_char *stack; - u_int32_t stackoffset; - u_char *stacklevels; - u_char *auth; - u_char *keep; - u_char *th_nodes; - u_char *retain; - treehash_inst *treehash; - - u_int32_t idx; /* state read from file */ - u_int32_t maxidx; /* restricted # of signatures */ - int have_state; /* .state file exists */ - int lockfd; /* locked in sshkey_xmss_get_state() */ - u_char allow_update; /* allow sshkey_xmss_update_state() */ - char *enc_ciphername;/* encrypt state with cipher */ - u_char *enc_keyiv; /* encrypt state with key */ - u_int32_t enc_keyiv_len; /* length of enc_keyiv */ -}; - -int sshkey_xmss_init_bds_state(struct sshkey *); -int sshkey_xmss_init_enc_key(struct sshkey *, const char *); -void sshkey_xmss_free_bds(struct sshkey *); -int sshkey_xmss_get_state_from_file(struct sshkey *, const char *, - int *, int); -int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *, - struct sshbuf **); -int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *, - struct sshbuf **); -int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *); - -#define PRINT(...) do { if (printerror) sshlog(__FILE__, __func__, __LINE__, \ - 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__); } while (0) - -int -sshkey_xmss_init(struct sshkey *key, const char *name) -{ - struct ssh_xmss_state *state; - - if (key->xmss_state != NULL) - return SSH_ERR_INVALID_FORMAT; - if (name == NULL) - return SSH_ERR_INVALID_FORMAT; - state = calloc(sizeof(struct ssh_xmss_state), 1); - if (state == NULL) - return SSH_ERR_ALLOC_FAIL; - if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 10; - } else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 16; - } else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 20; - } else { - free(state); - return SSH_ERR_KEY_TYPE_UNKNOWN; - } - if ((key->xmss_name = strdup(name)) == NULL) { - free(state); - return SSH_ERR_ALLOC_FAIL; - } - state->k = 2; /* XXX hardcoded */ - state->lockfd = -1; - if (xmss_set_params(&state->params, state->n, state->h, state->w, - state->k) != 0) { - free(state); - return SSH_ERR_INVALID_FORMAT; - } - key->xmss_state = state; - return 0; -} - -void -sshkey_xmss_free_state(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - sshkey_xmss_free_bds(key); - if (state) { - if (state->enc_keyiv) { - explicit_bzero(state->enc_keyiv, state->enc_keyiv_len); - free(state->enc_keyiv); - } - free(state->enc_ciphername); - free(state); - } - key->xmss_state = NULL; -} - -#define SSH_XMSS_K2_MAGIC "k=2" -#define num_stack(x) ((x->h+1)*(x->n)) -#define num_stacklevels(x) (x->h+1) -#define num_auth(x) ((x->h)*(x->n)) -#define num_keep(x) ((x->h >> 1)*(x->n)) -#define num_th_nodes(x) ((x->h - x->k)*(x->n)) -#define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n)) -#define num_treehash(x) ((x->h) - (x->k)) - -int -sshkey_xmss_init_bds_state(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - u_int32_t i; - - state->stackoffset = 0; - if ((state->stack = calloc(num_stack(state), 1)) == NULL || - (state->stacklevels = calloc(num_stacklevels(state), 1))== NULL || - (state->auth = calloc(num_auth(state), 1)) == NULL || - (state->keep = calloc(num_keep(state), 1)) == NULL || - (state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL || - (state->retain = calloc(num_retain(state), 1)) == NULL || - (state->treehash = calloc(num_treehash(state), - sizeof(treehash_inst))) == NULL) { - sshkey_xmss_free_bds(key); - return SSH_ERR_ALLOC_FAIL; - } - for (i = 0; i < state->h - state->k; i++) - state->treehash[i].node = &state->th_nodes[state->n*i]; - xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, - state->stacklevels, state->auth, state->keep, state->treehash, - state->retain, 0); - return 0; -} - -void -sshkey_xmss_free_bds(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return; - free(state->stack); - free(state->stacklevels); - free(state->auth); - free(state->keep); - free(state->th_nodes); - free(state->retain); - free(state->treehash); - state->stack = NULL; - state->stacklevels = NULL; - state->auth = NULL; - state->keep = NULL; - state->th_nodes = NULL; - state->retain = NULL; - state->treehash = NULL; -} - -void * -sshkey_xmss_params(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return NULL; - return &state->params; -} - -void * -sshkey_xmss_bds_state(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return NULL; - return &state->bds; -} - -int -sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (lenp == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (state == NULL) - return SSH_ERR_INVALID_FORMAT; - *lenp = 4 + state->n + - state->params.wots_par.keysize + - state->h * state->n; - return 0; -} - -size_t -sshkey_xmss_pklen(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return 0; - return state->n * 2; -} - -size_t -sshkey_xmss_sklen(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return 0; - return state->n * 4 + 4; -} - -int -sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername) -{ - struct ssh_xmss_state *state = k->xmss_state; - const struct sshcipher *cipher; - size_t keylen = 0, ivlen = 0; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((cipher = cipher_by_name(ciphername)) == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((state->enc_ciphername = strdup(ciphername)) == NULL) - return SSH_ERR_ALLOC_FAIL; - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - state->enc_keyiv_len = keylen + ivlen; - if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) { - free(state->enc_ciphername); - state->enc_ciphername = NULL; - return SSH_ERR_ALLOC_FAIL; - } - arc4random_buf(state->enc_keyiv, state->enc_keyiv_len); - return 0; -} - -int -sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - int r; - - if (state == NULL || state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 || - (r = sshbuf_put_string(b, state->enc_keyiv, - state->enc_keyiv_len)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - size_t len; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 || - (r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0) - return r; - state->enc_keyiv_len = len; - return 0; -} - -int -sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char have_info = 1; - u_int32_t idx; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (opts != SSHKEY_SERIALIZE_INFO) - return 0; - idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; - if ((r = sshbuf_put_u8(b, have_info)) != 0 || - (r = sshbuf_put_u32(b, idx)) != 0 || - (r = sshbuf_put_u32(b, state->maxidx)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char have_info; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - /* optional */ - if (sshbuf_len(b) == 0) - return 0; - if ((r = sshbuf_get_u8(b, &have_info)) != 0) - return r; - if (have_info != 1) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_get_u32(b, &state->idx)) != 0 || - (r = sshbuf_get_u32(b, &state->maxidx)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_generate_private_key(struct sshkey *k, int bits) -{ - int r; - const char *name; - - if (bits == 10) { - name = XMSS_SHA2_256_W16_H10_NAME; - } else if (bits == 16) { - name = XMSS_SHA2_256_W16_H16_NAME; - } else if (bits == 20) { - name = XMSS_SHA2_256_W16_H20_NAME; - } else { - name = XMSS_DEFAULT_NAME; - } - if ((r = sshkey_xmss_init(k, name)) != 0 || - (r = sshkey_xmss_init_bds_state(k)) != 0 || - (r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0) - return r; - if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL || - (k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) { - return SSH_ERR_ALLOC_FAIL; - } - xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k), - sshkey_xmss_params(k)); - return 0; -} - -int -sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename, - int *have_file, int printerror) -{ - struct sshbuf *b = NULL, *enc = NULL; - int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1; - u_int32_t len; - unsigned char buf[4], *data = NULL; - - *have_file = 0; - if ((fd = open(filename, O_RDONLY)) >= 0) { - *have_file = 1; - if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) { - PRINT("corrupt state file: %s", filename); - goto done; - } - len = PEEK_U32(buf); - if ((data = calloc(len, 1)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if (atomicio(read, fd, data, len) != len) { - PRINT("cannot read blob: %s", filename); - goto done; - } - if ((enc = sshbuf_from(data, len)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - sshkey_xmss_free_bds(k); - if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) { - ret = r; - goto done; - } - if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) { - ret = r; - goto done; - } - ret = 0; - } -done: - if (fd != -1) - close(fd); - free(data); - sshbuf_free(enc); - sshbuf_free(b); - return ret; -} - -int -sshkey_xmss_get_state(const struct sshkey *k, int printerror) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_int32_t idx = 0; - char *filename = NULL; - char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL; - int lockfd = -1, have_state = 0, have_ostate, tries = 0; - int ret = SSH_ERR_INVALID_ARGUMENT, r; - - if (state == NULL) - goto done; - /* - * If maxidx is set, then we are allowed a limited number - * of signatures, but don't need to access the disk. - * Otherwise we need to deal with the on-disk state. - */ - if (state->maxidx) { - /* xmss_sk always contains the current state */ - idx = PEEK_U32(k->xmss_sk); - if (idx < state->maxidx) { - state->allow_update = 1; - return 0; - } - return SSH_ERR_INVALID_ARGUMENT; - } - if ((filename = k->xmss_filename) == NULL) - goto done; - if (asprintf(&lockfile, "%s.lock", filename) == -1 || - asprintf(&statefile, "%s.state", filename) == -1 || - asprintf(&ostatefile, "%s.ostate", filename) == -1) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("cannot open/create: %s", lockfile); - goto done; - } - while (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { - if (errno != EWOULDBLOCK) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("cannot lock: %s", lockfile); - goto done; - } - if (++tries > 10) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("giving up on: %s", lockfile); - goto done; - } - usleep(1000*100*tries); - } - /* XXX no longer const */ - if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, - statefile, &have_state, printerror)) != 0) { - if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, - ostatefile, &have_ostate, printerror)) == 0) { - state->allow_update = 1; - r = sshkey_xmss_forward_state(k, 1); - state->idx = PEEK_U32(k->xmss_sk); - state->allow_update = 0; - } - } - if (!have_state && !have_ostate) { - /* check that bds state is initialized */ - if (state->bds.auth == NULL) - goto done; - PRINT("start from scratch idx 0: %u", state->idx); - } else if (r != 0) { - ret = r; - goto done; - } - if (state->idx + 1 < state->idx) { - PRINT("state wrap: %u", state->idx); - goto done; - } - state->have_state = have_state; - state->lockfd = lockfd; - state->allow_update = 1; - lockfd = -1; - ret = 0; -done: - if (lockfd != -1) - close(lockfd); - free(lockfile); - free(statefile); - free(ostatefile); - return ret; -} - -int -sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char *sig = NULL; - size_t required_siglen; - unsigned long long smlen; - u_char data; - int ret, r; - - if (state == NULL || !state->allow_update) - return SSH_ERR_INVALID_ARGUMENT; - if (reserve == 0) - return SSH_ERR_INVALID_ARGUMENT; - if (state->idx + reserve <= state->idx) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0) - return r; - if ((sig = malloc(required_siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - while (reserve-- > 0) { - state->idx = PEEK_U32(k->xmss_sk); - smlen = required_siglen; - if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k), - sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) { - r = SSH_ERR_INVALID_ARGUMENT; - break; - } - } - free(sig); - return r; -} - -int -sshkey_xmss_update_state(const struct sshkey *k, int printerror) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *b = NULL, *enc = NULL; - u_int32_t idx = 0; - unsigned char buf[4]; - char *filename = NULL; - char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL; - int fd = -1; - int ret = SSH_ERR_INVALID_ARGUMENT; - - if (state == NULL || !state->allow_update) - return ret; - if (state->maxidx) { - /* no update since the number of signatures is limited */ - ret = 0; - goto done; - } - idx = PEEK_U32(k->xmss_sk); - if (idx == state->idx) { - /* no signature happened, no need to update */ - ret = 0; - goto done; - } else if (idx != state->idx + 1) { - PRINT("more than one signature happened: idx %u state %u", - idx, state->idx); - goto done; - } - state->idx = idx; - if ((filename = k->xmss_filename) == NULL) - goto done; - if (asprintf(&statefile, "%s.state", filename) == -1 || - asprintf(&ostatefile, "%s.ostate", filename) == -1 || - asprintf(&nstatefile, "%s.nstate", filename) == -1) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - unlink(nstatefile); - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) { - PRINT("SERLIALIZE FAILED: %d", ret); - goto done; - } - if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) { - PRINT("ENCRYPT FAILED: %d", ret); - goto done; - } - if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("open new state file: %s", nstatefile); - goto done; - } - POKE_U32(buf, sshbuf_len(enc)); - if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("write new state file hdr: %s", nstatefile); - close(fd); - goto done; - } - if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) != - sshbuf_len(enc)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("write new state file data: %s", nstatefile); - close(fd); - goto done; - } - if (fsync(fd) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("sync new state file: %s", nstatefile); - close(fd); - goto done; - } - if (close(fd) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("close new state file: %s", nstatefile); - goto done; - } - if (state->have_state) { - unlink(ostatefile); - if (link(statefile, ostatefile)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("backup state %s to %s", statefile, ostatefile); - goto done; - } - } - if (rename(nstatefile, statefile) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("rename %s to %s", nstatefile, statefile); - goto done; - } - ret = 0; -done: - if (state->lockfd != -1) { - close(state->lockfd); - state->lockfd = -1; - } - if (nstatefile) - unlink(nstatefile); - free(statefile); - free(ostatefile); - free(nstatefile); - sshbuf_free(b); - sshbuf_free(enc); - return ret; -} - -int -sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - treehash_inst *th; - u_int32_t i, node; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (state->stack == NULL) - return SSH_ERR_INVALID_ARGUMENT; - state->stackoffset = state->bds.stackoffset; /* copy back */ - if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 || - (r = sshbuf_put_u32(b, state->idx)) != 0 || - (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 || - (r = sshbuf_put_u32(b, state->stackoffset)) != 0 || - (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 || - (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 || - (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 || - (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 || - (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 || - (r = sshbuf_put_u32(b, num_treehash(state))) != 0) - return r; - for (i = 0; i < num_treehash(state); i++) { - th = &state->treehash[i]; - node = th->node - state->th_nodes; - if ((r = sshbuf_put_u32(b, th->h)) != 0 || - (r = sshbuf_put_u32(b, th->next_idx)) != 0 || - (r = sshbuf_put_u32(b, th->stackusage)) != 0 || - (r = sshbuf_put_u8(b, th->completed)) != 0 || - (r = sshbuf_put_u32(b, node)) != 0) - return r; - } - return 0; -} - -int -sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - struct ssh_xmss_state *state = k->xmss_state; - int r = SSH_ERR_INVALID_ARGUMENT; - u_char have_stack, have_filename, have_enc; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_u8(b, opts)) != 0) - return r; - switch (opts) { - case SSHKEY_SERIALIZE_STATE: - r = sshkey_xmss_serialize_state(k, b); - break; - case SSHKEY_SERIALIZE_FULL: - if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0) - return r; - r = sshkey_xmss_serialize_state(k, b); - break; - case SSHKEY_SERIALIZE_SHIELD: - /* all of stack/filename/enc are optional */ - have_stack = state->stack != NULL; - if ((r = sshbuf_put_u8(b, have_stack)) != 0) - return r; - if (have_stack) { - state->idx = PEEK_U32(k->xmss_sk); /* update */ - if ((r = sshkey_xmss_serialize_state(k, b)) != 0) - return r; - } - have_filename = k->xmss_filename != NULL; - if ((r = sshbuf_put_u8(b, have_filename)) != 0) - return r; - if (have_filename && - (r = sshbuf_put_cstring(b, k->xmss_filename)) != 0) - return r; - have_enc = state->enc_keyiv != NULL; - if ((r = sshbuf_put_u8(b, have_enc)) != 0) - return r; - if (have_enc && - (r = sshkey_xmss_serialize_enc_key(k, b)) != 0) - return r; - if ((r = sshbuf_put_u32(b, state->maxidx)) != 0 || - (r = sshbuf_put_u8(b, state->allow_update)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_DEFAULT: - r = 0; - break; - default: - r = SSH_ERR_INVALID_ARGUMENT; - break; - } - return r; -} - -int -sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - treehash_inst *th; - u_int32_t i, lh, node; - size_t ls, lsl, la, lk, ln, lr; - char *magic; - int r = SSH_ERR_INTERNAL_ERROR; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (k->xmss_sk == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((state->treehash = calloc(num_treehash(state), - sizeof(treehash_inst))) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 || - (r = sshbuf_get_u32(b, &state->idx)) != 0 || - (r = sshbuf_get_string(b, &state->stack, &ls)) != 0 || - (r = sshbuf_get_u32(b, &state->stackoffset)) != 0 || - (r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 || - (r = sshbuf_get_string(b, &state->auth, &la)) != 0 || - (r = sshbuf_get_string(b, &state->keep, &lk)) != 0 || - (r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 || - (r = sshbuf_get_string(b, &state->retain, &lr)) != 0 || - (r = sshbuf_get_u32(b, &lh)) != 0) - goto out; - if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - /* XXX check stackoffset */ - if (ls != num_stack(state) || - lsl != num_stacklevels(state) || - la != num_auth(state) || - lk != num_keep(state) || - ln != num_th_nodes(state) || - lr != num_retain(state) || - lh != num_treehash(state)) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - for (i = 0; i < num_treehash(state); i++) { - th = &state->treehash[i]; - if ((r = sshbuf_get_u32(b, &th->h)) != 0 || - (r = sshbuf_get_u32(b, &th->next_idx)) != 0 || - (r = sshbuf_get_u32(b, &th->stackusage)) != 0 || - (r = sshbuf_get_u8(b, &th->completed)) != 0 || - (r = sshbuf_get_u32(b, &node)) != 0) - goto out; - if (node < num_th_nodes(state)) - th->node = &state->th_nodes[node]; - } - POKE_U32(k->xmss_sk, state->idx); - xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, - state->stacklevels, state->auth, state->keep, state->treehash, - state->retain, 0); - /* success */ - r = 0; - out: - free(magic); - return r; -} - -int -sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - enum sshkey_serialize_rep opts; - u_char have_state, have_stack, have_filename, have_enc; - int r; - - if ((r = sshbuf_get_u8(b, &have_state)) != 0) - return r; - - opts = have_state; - switch (opts) { - case SSHKEY_SERIALIZE_DEFAULT: - r = 0; - break; - case SSHKEY_SERIALIZE_SHIELD: - if ((r = sshbuf_get_u8(b, &have_stack)) != 0) - return r; - if (have_stack && - (r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - if ((r = sshbuf_get_u8(b, &have_filename)) != 0) - return r; - if (have_filename && - (r = sshbuf_get_cstring(b, &k->xmss_filename, NULL)) != 0) - return r; - if ((r = sshbuf_get_u8(b, &have_enc)) != 0) - return r; - if (have_enc && - (r = sshkey_xmss_deserialize_enc_key(k, b)) != 0) - return r; - if ((r = sshbuf_get_u32(b, &state->maxidx)) != 0 || - (r = sshbuf_get_u8(b, &state->allow_update)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_STATE: - if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_FULL: - if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 || - (r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - break; - default: - r = SSH_ERR_INVALID_FORMAT; - break; - } - return r; -} - -int -sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, - struct sshbuf **retp) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; - struct sshcipher_ctx *ciphercontext = NULL; - const struct sshcipher *cipher; - u_char *cp, *key, *iv = NULL; - size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; - int r = SSH_ERR_INTERNAL_ERROR; - - if (retp != NULL) - *retp = NULL; - if (state == NULL || - state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { - r = SSH_ERR_INTERNAL_ERROR; - goto out; - } - blocksize = cipher_blocksize(cipher); - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - authlen = cipher_authlen(cipher); - if (state->enc_keyiv_len != keylen + ivlen) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - key = state->enc_keyiv; - if ((encrypted = sshbuf_new()) == NULL || - (encoded = sshbuf_new()) == NULL || - (padded = sshbuf_new()) == NULL || - (iv = malloc(ivlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* replace first 4 bytes of IV with index to ensure uniqueness */ - memcpy(iv, key + keylen, ivlen); - POKE_U32(iv, state->idx); - - if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || - (r = sshbuf_put_u32(encoded, state->idx)) != 0) - goto out; - - /* padded state will be encrypted */ - if ((r = sshbuf_putb(padded, b)) != 0) - goto out; - i = 0; - while (sshbuf_len(padded) % blocksize) { - if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) - goto out; - } - encrypted_len = sshbuf_len(padded); - - /* header including the length of state is used as AAD */ - if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) - goto out; - aadlen = sshbuf_len(encoded); - - /* concat header and state */ - if ((r = sshbuf_putb(encoded, padded)) != 0) - goto out; - - /* reserve space for encryption of encoded data plus auth tag */ - /* encrypt at offset addlen */ - if ((r = sshbuf_reserve(encrypted, - encrypted_len + aadlen + authlen, &cp)) != 0 || - (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 1)) != 0 || - (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), - encrypted_len, aadlen, authlen)) != 0) - goto out; - - /* success */ - r = 0; - out: - if (retp != NULL) { - *retp = encrypted; - encrypted = NULL; - } - sshbuf_free(padded); - sshbuf_free(encoded); - sshbuf_free(encrypted); - cipher_free(ciphercontext); - free(iv); - return r; -} - -int -sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, - struct sshbuf **retp) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *copy = NULL, *decrypted = NULL; - struct sshcipher_ctx *ciphercontext = NULL; - const struct sshcipher *cipher = NULL; - u_char *key, *iv = NULL, *dp; - size_t keylen, ivlen, authlen, aadlen; - u_int blocksize, encrypted_len, index; - int r = SSH_ERR_INTERNAL_ERROR; - - if (retp != NULL) - *retp = NULL; - if (state == NULL || - state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - blocksize = cipher_blocksize(cipher); - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - authlen = cipher_authlen(cipher); - if (state->enc_keyiv_len != keylen + ivlen) { - r = SSH_ERR_INTERNAL_ERROR; - goto out; - } - key = state->enc_keyiv; - - if ((copy = sshbuf_fromb(encoded)) == NULL || - (decrypted = sshbuf_new()) == NULL || - (iv = malloc(ivlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* check magic */ - if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || - memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - /* parse public portion */ - if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || - (r = sshbuf_get_u32(encoded, &index)) != 0 || - (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) - goto out; - - /* check size of encrypted key blob */ - if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - /* check that an appropriate amount of auth data is present */ - if (sshbuf_len(encoded) < authlen || - sshbuf_len(encoded) - authlen < encrypted_len) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - - aadlen = sshbuf_len(copy) - sshbuf_len(encoded); - - /* replace first 4 bytes of IV with index to ensure uniqueness */ - memcpy(iv, key + keylen, ivlen); - POKE_U32(iv, index); - - /* decrypt private state of key */ - if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || - (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 0)) != 0 || - (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), - encrypted_len, aadlen, authlen)) != 0) - goto out; - - /* there should be no trailing data */ - if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) - goto out; - if (sshbuf_len(encoded) != 0) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - - /* remove AAD */ - if ((r = sshbuf_consume(decrypted, aadlen)) != 0) - goto out; - /* XXX encrypted includes unchecked padding */ - - /* success */ - r = 0; - if (retp != NULL) { - *retp = decrypted; - decrypted = NULL; - } - out: - cipher_free(ciphercontext); - sshbuf_free(copy); - sshbuf_free(decrypted); - free(iv); - return r; -} - -u_int32_t -sshkey_xmss_signatures_left(const struct sshkey *k) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_int32_t idx; - - if (sshkey_type_plain(k->type) == KEY_XMSS && state && - state->maxidx) { - idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; - if (idx < state->maxidx) - return state->maxidx - idx; - } - return 0; -} - -int -sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - struct ssh_xmss_state *state = k->xmss_state; - - if (sshkey_type_plain(k->type) != KEY_XMSS) - return SSH_ERR_INVALID_ARGUMENT; - if (maxsign == 0) - return 0; - if (state->idx + maxsign < state->idx) - return SSH_ERR_INVALID_ARGUMENT; - state->maxidx = state->idx + maxsign; - return 0; -} -#endif /* WITH_XMSS */ diff --git a/sshkey-xmss.h b/sshkey-xmss.h deleted file mode 100644 index ab8b9c905..000000000 --- a/sshkey-xmss.h +++ /dev/null @@ -1,56 +0,0 @@ -/* $OpenBSD: sshkey-xmss.h,v 1.4 2022/10/28 00:39:29 djm Exp $ */ -/* - * Copyright (c) 2017 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef SSHKEY_XMSS_H -#define SSHKEY_XMSS_H - -#define XMSS_SHA2_256_W16_H10_NAME "XMSS_SHA2-256_W16_H10" -#define XMSS_SHA2_256_W16_H16_NAME "XMSS_SHA2-256_W16_H16" -#define XMSS_SHA2_256_W16_H20_NAME "XMSS_SHA2-256_W16_H20" -#define XMSS_DEFAULT_NAME XMSS_SHA2_256_W16_H10_NAME - -size_t sshkey_xmss_pklen(const struct sshkey *); -size_t sshkey_xmss_sklen(const struct sshkey *); -int sshkey_xmss_init(struct sshkey *, const char *); -void sshkey_xmss_free_state(struct sshkey *); -int sshkey_xmss_generate_private_key(struct sshkey *, int); -int sshkey_xmss_serialize_state(const struct sshkey *, struct sshbuf *); -int sshkey_xmss_serialize_state_opt(const struct sshkey *, struct sshbuf *, - enum sshkey_serialize_rep); -int sshkey_xmss_serialize_pk_info(const struct sshkey *, struct sshbuf *, - enum sshkey_serialize_rep); -int sshkey_xmss_deserialize_state(struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_state_opt(struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_pk_info(struct sshkey *, struct sshbuf *); - -int sshkey_xmss_siglen(const struct sshkey *, size_t *); -void *sshkey_xmss_params(const struct sshkey *); -void *sshkey_xmss_bds_state(const struct sshkey *); -int sshkey_xmss_get_state(const struct sshkey *, int); -int sshkey_xmss_enable_maxsign(struct sshkey *, u_int32_t); -int sshkey_xmss_forward_state(const struct sshkey *, u_int32_t); -int sshkey_xmss_update_state(const struct sshkey *, int); -u_int32_t sshkey_xmss_signatures_left(const struct sshkey *); - -#endif /* SSHKEY_XMSS_H */ diff --git a/sshkey.c b/sshkey.c index 3b1335d99..6b3e24ec4 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.151 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.152 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -62,11 +62,6 @@ #include "ssh-sk.h" #include "ssh-pkcs11.h" -#ifdef WITH_XMSS -#include "sshkey-xmss.h" -#include "xmss_fast.h" -#endif - #include "openbsd-compat/openssl-compat.h" /* openssh private key file format */ @@ -88,8 +83,6 @@ #define SSHKEY_SHIELD_CIPHER "aes256-ctr" /* XXX want AES-EME* */ #define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512 -int sshkey_private_serialize_opt(struct sshkey *key, - struct sshbuf *buf, enum sshkey_serialize_rep); static int sshkey_from_blob_internal(struct sshbuf *buf, struct sshkey **keyp, int allow_cert); @@ -121,10 +114,6 @@ extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl; extern const struct sshkey_impl sshkey_rsa_sha512_impl; extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; #endif /* WITH_OPENSSL */ -#ifdef WITH_XMSS -extern const struct sshkey_impl sshkey_xmss_impl; -extern const struct sshkey_impl sshkey_xmss_cert_impl; -#endif const struct sshkey_impl * const keyimpls[] = { &sshkey_ed25519_impl, @@ -156,10 +145,6 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_rsa_sha512_impl, &sshkey_rsa_sha512_cert_impl, #endif /* WITH_OPENSSL */ -#ifdef WITH_XMSS - &sshkey_xmss_impl, - &sshkey_xmss_cert_impl, -#endif NULL }; @@ -452,8 +437,6 @@ sshkey_type_plain(int type) return KEY_ED25519; case KEY_ED25519_SK_CERT: return KEY_ED25519_SK; - case KEY_XMSS_CERT: - return KEY_XMSS; default: return type; } @@ -474,8 +457,6 @@ sshkey_type_certified(int type) return KEY_ED25519_CERT; case KEY_ED25519_SK: return KEY_ED25519_SK_CERT; - case KEY_XMSS: - return KEY_XMSS_CERT; default: return -1; } @@ -919,17 +900,10 @@ sshkey_puts_opts_internal(const struct sshkey *key, struct sshbuf *b, 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 sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT); + return sshkey_puts_opts_internal(key, b, SSHKEY_SERIALIZE_DEFAULT, 0); } int @@ -1691,8 +1665,7 @@ sshkey_shield_private(struct sshkey *k) } if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0) goto out; - if ((r = sshkey_private_serialize_opt(k, prvbuf, - SSHKEY_SERIALIZE_SHIELD)) != 0) + if ((r = sshkey_private_serialize(k, prvbuf)) != 0) goto out; /* pad to cipher blocksize */ i = 0; @@ -2550,7 +2523,7 @@ sshkey_serialize_private_sk(const struct sshkey *key, struct sshbuf *b) return 0; } -int +static int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, enum sshkey_serialize_rep opts) { @@ -2601,6 +2574,7 @@ sshkey_private_serialize(struct sshkey *key, struct sshbuf *b) SSHKEY_SERIALIZE_DEFAULT); } + /* Shared deserialization of FIDO private key components */ int sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k) @@ -2660,7 +2634,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) expect_ed25519_pk = k->ed25519_pk; k->sk_application = NULL; k->ed25519_pk = NULL; - /* XXX xmss too or refactor */ } else { if ((k = sshkey_new(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; @@ -2674,7 +2647,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) if ((r = impl->funcs->deserialize_private(tname, buf, k)) != 0) goto out; - /* XXX xmss too or refactor */ if ((expect_sk_application != NULL && (k->sk_application == NULL || strcmp(expect_sk_application, k->sk_application) != 0)) || (expect_ed25519_pk != NULL && (k->ed25519_pk == NULL || @@ -2919,8 +2891,7 @@ sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, goto out; /* append private key and comment*/ - if ((r = sshkey_private_serialize_opt(prv, encrypted, - SSHKEY_SERIALIZE_FULL)) != 0 || + if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || (r = sshbuf_put_cstring(encrypted, comment)) != 0) goto out; @@ -3400,9 +3371,6 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_SK: -#ifdef WITH_XMSS - case KEY_XMSS: -#endif /* WITH_XMSS */ #ifdef WITH_OPENSSL case KEY_ECDSA_SK: #endif /* WITH_OPENSSL */ @@ -3664,24 +3632,16 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, if (commentp != NULL) *commentp = NULL; - switch (type) { - case KEY_XMSS: - /* No fallback for new-format-only keys */ - return sshkey_parse_private2(blob, type, passphrase, - keyp, commentp); - default: - r = sshkey_parse_private2(blob, type, passphrase, keyp, - commentp); - /* Only fallback to PEM parser if a format error occurred. */ - if (r != SSH_ERR_INVALID_FORMAT) - return r; + r = sshkey_parse_private2(blob, type, passphrase, keyp, commentp); + /* Only fallback to PEM parser if a format error occurred. */ + if (r != SSH_ERR_INVALID_FORMAT) + return r; #ifdef WITH_OPENSSL - return sshkey_parse_private_pem_fileblob(blob, type, - passphrase, keyp); + return sshkey_parse_private_pem_fileblob(blob, type, + passphrase, keyp); #else - return SSH_ERR_INVALID_FORMAT; + return SSH_ERR_INVALID_FORMAT; #endif /* WITH_OPENSSL */ - } } int @@ -3716,90 +3676,3 @@ sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type, return r; return 0; } - -#ifdef WITH_XMSS -/* - * serialize the key with the current state and forward the state - * maxsign times. - */ -int -sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b, - u_int32_t maxsign, int printerror) -{ - int r, rupdate; - - if (maxsign == 0 || - sshkey_type_plain(k->type) != KEY_XMSS) - return sshkey_private_serialize_opt(k, b, - SSHKEY_SERIALIZE_DEFAULT); - if ((r = sshkey_xmss_get_state(k, printerror)) != 0 || - (r = sshkey_private_serialize_opt(k, b, - SSHKEY_SERIALIZE_STATE)) != 0 || - (r = sshkey_xmss_forward_state(k, maxsign)) != 0) - goto out; - r = 0; -out: - if ((rupdate = sshkey_xmss_update_state(k, printerror)) != 0) { - if (r == 0) - r = rupdate; - } - return r; -} - -u_int32_t -sshkey_signatures_left(const struct sshkey *k) -{ - if (sshkey_type_plain(k->type) == KEY_XMSS) - return sshkey_xmss_signatures_left(k); - return 0; -} - -int -sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - if (sshkey_type_plain(k->type) != KEY_XMSS) - return SSH_ERR_INVALID_ARGUMENT; - return sshkey_xmss_enable_maxsign(k, maxsign); -} - -int -sshkey_set_filename(struct sshkey *k, const char *filename) -{ - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (sshkey_type_plain(k->type) != KEY_XMSS) - return 0; - if (filename == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((k->xmss_filename = strdup(filename)) == NULL) - return SSH_ERR_ALLOC_FAIL; - return 0; -} -#else -int -sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b, - u_int32_t maxsign, int printerror) -{ - return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT); -} - -u_int32_t -sshkey_signatures_left(const struct sshkey *k) -{ - return 0; -} - -int -sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - return SSH_ERR_INVALID_ARGUMENT; -} - -int -sshkey_set_filename(struct sshkey *k, const char *filename) -{ - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; - return 0; -} -#endif /* WITH_XMSS */ diff --git a/sshkey.h b/sshkey.h index 77253bc4e..c3262b896 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.69 2025/07/24 06:12:08 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.70 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -63,8 +63,6 @@ enum sshkey_types { KEY_RSA_CERT, KEY_ECDSA_CERT, KEY_ED25519_CERT, - KEY_XMSS, - KEY_XMSS_CERT, KEY_ECDSA_SK, KEY_ECDSA_SK_CERT, KEY_ED25519_SK, @@ -87,10 +85,6 @@ enum sshkey_fp_rep { /* Private key serialisation formats, used on the wire */ enum sshkey_serialize_rep { SSHKEY_SERIALIZE_DEFAULT = 0, - SSHKEY_SERIALIZE_STATE = 1, /* only state is serialized */ - SSHKEY_SERIALIZE_FULL = 2, /* include keys for saving to disk */ - SSHKEY_SERIALIZE_SHIELD = 3, /* everything, for encrypting in ram */ - SSHKEY_SERIALIZE_INFO = 254, /* minimal information */ }; /* Private key disk formats */ @@ -130,12 +124,6 @@ struct sshkey { /* KEY_ED25519 and KEY_ED25519_SK */ u_char *ed25519_sk; u_char *ed25519_pk; - /* KEY_XMSS */ - char *xmss_name; - char *xmss_filename; /* for state file updates */ - void *xmss_state; /* depends on xmss_name, opaque */ - u_char *xmss_sk; - u_char *xmss_pk; /* KEY_ECDSA_SK and KEY_ED25519_SK */ char *sk_application; uint8_t sk_flags; @@ -271,8 +259,6 @@ int sshkey_to_blob(const struct sshkey *, u_char **, size_t *); int sshkey_to_base64(const struct sshkey *, char **); int sshkey_putb(const struct sshkey *, struct sshbuf *); int sshkey_puts(const struct sshkey *, struct sshbuf *); -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 *); @@ -297,8 +283,6 @@ void sshkey_dump_ec_key(const EC_KEY *); /* private key parsing and serialisation */ int sshkey_private_serialize(struct sshkey *key, struct sshbuf *buf); -int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, - enum sshkey_serialize_rep); int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp); /* private key file format parsing and serialisation */ @@ -325,13 +309,6 @@ int ssh_ed25519_encode_store_sig(const u_char *, size_t, int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **); -/* stateful keys (e.g. XMSS) */ -int sshkey_set_filename(struct sshkey *, const char *); -int sshkey_enable_maxsign(struct sshkey *, u_int32_t); -u_int32_t sshkey_signatures_left(const struct sshkey *); -int sshkey_private_serialize_maxsign(struct sshkey *key, - struct sshbuf *buf, u_int32_t maxsign, int); - void sshkey_sig_details_free(struct sshkey_sig_details *); #ifdef WITH_OPENSSL diff --git a/xmss_commons.c b/xmss_commons.c deleted file mode 100644 index 8d6b80b6e..000000000 --- a/xmss_commons.c +++ /dev/null @@ -1,36 +0,0 @@ -/* $OpenBSD: xmss_commons.c,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_commons.c 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include "xmss_commons.h" -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif - -void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes) -{ - int32_t i; - for (i = bytes-1; i >= 0; i--) { - out[i] = in & 0xff; - in = in >> 8; - } -} - -#if 0 -void hexdump(const unsigned char *a, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) - printf("%02x", a[i]); -} -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_commons.h b/xmss_commons.h deleted file mode 100644 index a98e4799c..000000000 --- a/xmss_commons.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_commons.h,v 1.3 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_commons.h 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ -#ifndef XMSS_COMMONS_H -#define XMSS_COMMONS_H - -#include -#ifdef HAVE_STDINT_H -#include -#endif -#endif -void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes); -#if 0 -void hexdump(const unsigned char *a, size_t len); -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_fast.c b/xmss_fast.c deleted file mode 100644 index 421b39a37..000000000 --- a/xmss_fast.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* $OpenBSD: xmss_fast.c,v 1.3 2018/03/22 07:06:11 markus Exp $ */ -/* -xmss_fast.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif - -#include "xmss_fast.h" -#include "crypto_api.h" -#include "xmss_wots.h" -#include "xmss_hash.h" - -#include "xmss_commons.h" -#include "xmss_hash_address.h" -// For testing -#include "stdio.h" - - - -/** - * Used for pseudorandom keygeneration, - * generates the seed for the WOTS keypair at address addr - * - * takes n byte sk_seed and returns n byte seed using 32 byte address addr. - */ -static void get_seed(unsigned char *seed, const unsigned char *sk_seed, int n, uint32_t addr[8]) -{ - unsigned char bytes[32]; - // Make sure that chain addr, hash addr, and key bit are 0! - setChainADRS(addr,0); - setHashADRS(addr,0); - setKeyAndMask(addr,0); - // Generate pseudorandom value - addr_to_byte(bytes, addr); - prf(seed, bytes, sk_seed, n); -} - -/** - * Initialize xmss params struct - * parameter names are the same as in the draft - * parameter k is K as used in the BDS algorithm - */ -int xmss_set_params(xmss_params *params, int n, int h, int w, int k) -{ - if (k >= h || k < 2 || (h - k) % 2) { - fprintf(stderr, "For BDS traversal, H - K must be even, with H > K >= 2!\n"); - return 1; - } - params->h = h; - params->n = n; - params->k = k; - wots_params wots_par; - wots_set_params(&wots_par, n, w); - params->wots_par = wots_par; - return 0; -} - -/** - * Initialize BDS state struct - * parameter names are the same as used in the description of the BDS traversal - */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf) -{ - state->stack = stack; - state->stackoffset = stackoffset; - state->stacklevels = stacklevels; - state->auth = auth; - state->keep = keep; - state->treehash = treehash; - state->retain = retain; - state->next_leaf = next_leaf; -} - -/** - * Initialize xmssmt_params struct - * parameter names are the same as in the draft - * - * Especially h is the total tree height, i.e. the XMSS trees have height h/d - */ -int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k) -{ - if (h % d) { - fprintf(stderr, "d must divide h without remainder!\n"); - return 1; - } - params->h = h; - params->d = d; - params->n = n; - params->index_len = (h + 7) / 8; - xmss_params xmss_par; - if (xmss_set_params(&xmss_par, n, (h/d), w, k)) { - return 1; - } - params->xmss_par = xmss_par; - return 0; -} - -/** - * Computes a leaf from a WOTS public key using an L-tree. - */ -static void l_tree(unsigned char *leaf, unsigned char *wots_pk, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int l = params->wots_par.len; - unsigned int n = params->n; - uint32_t i = 0; - uint32_t height = 0; - uint32_t bound; - - //ADRS.setTreeHeight(0); - setTreeHeight(addr, height); - - while (l > 1) { - bound = l >> 1; //floor(l / 2); - for (i = 0; i < bound; i++) { - //ADRS.setTreeIndex(i); - setTreeIndex(addr, i); - //wots_pk[i] = RAND_HASH(pk[2i], pk[2i + 1], SEED, ADRS); - hash_h(wots_pk+i*n, wots_pk+i*2*n, pub_seed, addr, n); - } - //if ( l % 2 == 1 ) { - if (l & 1) { - //pk[floor(l / 2) + 1] = pk[l]; - memcpy(wots_pk+(l>>1)*n, wots_pk+(l-1)*n, n); - //l = ceil(l / 2); - l=(l>>1)+1; - } - else { - //l = ceil(l / 2); - l=(l>>1); - } - //ADRS.setTreeHeight(ADRS.getTreeHeight() + 1); - height++; - setTreeHeight(addr, height); - } - //return pk[0]; - memcpy(leaf, wots_pk, n); -} - -/** - * Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. - */ -static void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8]) -{ - unsigned char seed[params->n]; - unsigned char pk[params->wots_par.keysize]; - - get_seed(seed, sk_seed, params->n, ots_addr); - wots_pkgen(pk, seed, &(params->wots_par), pub_seed, ots_addr); - - l_tree(leaf, pk, params, pub_seed, ltree_addr); -} - -static int treehash_minheight_on_stack(bds_state* state, const xmss_params *params, const treehash_inst *treehash) { - unsigned int r = params->h, i; - for (i = 0; i < treehash->stackusage; i++) { - if (state->stacklevels[state->stackoffset - i - 1] < r) { - r = state->stacklevels[state->stackoffset - i - 1]; - } - } - return r; -} - -/** - * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash. - * Currently only used for key generation. - * - */ -static void treehash_setup(unsigned char *node, int height, int index, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8]) -{ - unsigned int idx = index; - unsigned int n = params->n; - unsigned int h = params->h; - unsigned int k = params->k; - // use three different addresses because at this point we use all three formats in parallel - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - uint32_t lastnode, i; - unsigned char stack[(height+1)*n]; - unsigned int stacklevels[height+1]; - unsigned int stackoffset=0; - unsigned int nodeh; - - lastnode = idx+(1<treehash[i].h = i; - state->treehash[i].completed = 1; - state->treehash[i].stackusage = 0; - } - - i = 0; - for (; idx < lastnode; idx++) { - setLtreeADRS(ltree_addr, idx); - setOTSADRS(ots_addr, idx); - gen_leaf_wots(stack+stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr); - stacklevels[stackoffset] = 0; - stackoffset++; - if (h - k > 0 && i == 3) { - memcpy(state->treehash[0].node, stack+stackoffset*n, n); - } - while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) - { - nodeh = stacklevels[stackoffset-1]; - if (i >> nodeh == 1) { - memcpy(state->auth + nodeh*n, stack+(stackoffset-1)*n, n); - } - else { - if (nodeh < h - k && i >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*n, n); - } - else if (nodeh >= h - k) { - memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((i >> nodeh) - 3) >> 1)) * n, stack+(stackoffset-1)*n, n); - } - } - setTreeHeight(node_addr, stacklevels[stackoffset-1]); - setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); - hash_h(stack+(stackoffset-2)*n, stack+(stackoffset-2)*n, pub_seed, - node_addr, n); - stacklevels[stackoffset-2]++; - stackoffset--; - } - i++; - } - - for (i = 0; i < n; i++) - node[i] = stack[i]; -} - -static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8]) { - int n = params->n; - - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setLtreeADRS(ltree_addr, treehash->next_idx); - setOTSADRS(ots_addr, treehash->next_idx); - - unsigned char nodebuffer[2 * n]; - unsigned int nodeheight = 0; - gen_leaf_wots(nodebuffer, sk_seed, params, pub_seed, ltree_addr, ots_addr); - while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) { - memcpy(nodebuffer + n, nodebuffer, n); - memcpy(nodebuffer, state->stack + (state->stackoffset-1)*n, n); - setTreeHeight(node_addr, nodeheight); - setTreeIndex(node_addr, (treehash->next_idx >> (nodeheight+1))); - hash_h(nodebuffer, nodebuffer, pub_seed, node_addr, n); - nodeheight++; - treehash->stackusage--; - state->stackoffset--; - } - if (nodeheight == treehash->h) { // this also implies stackusage == 0 - memcpy(treehash->node, nodebuffer, n); - treehash->completed = 1; - } - else { - memcpy(state->stack + state->stackoffset*n, nodebuffer, n); - treehash->stackusage++; - state->stacklevels[state->stackoffset] = nodeheight; - state->stackoffset++; - treehash->next_idx++; - } -} - -/** - * Computes a root node given a leaf and an authapth - */ -static void validate_authpath(unsigned char *root, const unsigned char *leaf, unsigned long leafidx, const unsigned char *authpath, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int n = params->n; - - uint32_t i, j; - unsigned char buffer[2*n]; - - // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. - // Otherwise, it is the other way around - if (leafidx & 1) { - for (j = 0; j < n; j++) - buffer[n+j] = leaf[j]; - for (j = 0; j < n; j++) - buffer[j] = authpath[j]; - } - else { - for (j = 0; j < n; j++) - buffer[j] = leaf[j]; - for (j = 0; j < n; j++) - buffer[n+j] = authpath[j]; - } - authpath += n; - - for (i=0; i < params->h-1; i++) { - setTreeHeight(addr, i); - leafidx >>= 1; - setTreeIndex(addr, leafidx); - if (leafidx&1) { - hash_h(buffer+n, buffer, pub_seed, addr, n); - for (j = 0; j < n; j++) - buffer[j] = authpath[j]; - } - else { - hash_h(buffer, buffer, pub_seed, addr, n); - for (j = 0; j < n; j++) - buffer[j+n] = authpath[j]; - } - authpath += n; - } - setTreeHeight(addr, (params->h-1)); - leafidx >>= 1; - setTreeIndex(addr, leafidx); - hash_h(root, buffer, pub_seed, addr, n); -} - -/** - * Performs one treehash update on the instance that needs it the most. - * Returns 1 if such an instance was not found - **/ -static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t i, j; - unsigned int level, l_min, low; - unsigned int h = params->h; - unsigned int k = params->k; - unsigned int used = 0; - - for (j = 0; j < updates; j++) { - l_min = h; - level = h - k; - for (i = 0; i < h - k; i++) { - if (state->treehash[i].completed) { - low = h; - } - else if (state->treehash[i].stackusage == 0) { - low = i; - } - else { - low = treehash_minheight_on_stack(state, params, &(state->treehash[i])); - } - if (low < l_min) { - level = i; - l_min = low; - } - } - if (level == h - k) { - break; - } - treehash_update(&(state->treehash[level]), state, sk_seed, params, pub_seed, addr); - used++; - } - return updates - used; -} - -/** - * Updates the state (typically NEXT_i) by adding a leaf and updating the stack - * Returns 1 if all leaf nodes have already been processed - **/ -static char bds_state_update(bds_state *state, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - uint32_t ots_addr[8]; - - int n = params->n; - int h = params->h; - int k = params->k; - - int nodeh; - int idx = state->next_leaf; - if (idx == 1 << h) { - return 1; - } - - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx); - setLtreeADRS(ltree_addr, idx); - - gen_leaf_wots(state->stack+state->stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr); - - state->stacklevels[state->stackoffset] = 0; - state->stackoffset++; - if (h - k > 0 && idx == 3) { - memcpy(state->treehash[0].node, state->stack+state->stackoffset*n, n); - } - while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) { - nodeh = state->stacklevels[state->stackoffset-1]; - if (idx >> nodeh == 1) { - memcpy(state->auth + nodeh*n, state->stack+(state->stackoffset-1)*n, n); - } - else { - if (nodeh < h - k && idx >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*n, n); - } - else if (nodeh >= h - k) { - memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((idx >> nodeh) - 3) >> 1)) * n, state->stack+(state->stackoffset-1)*n, n); - } - } - setTreeHeight(node_addr, state->stacklevels[state->stackoffset-1]); - setTreeIndex(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1))); - hash_h(state->stack+(state->stackoffset-2)*n, state->stack+(state->stackoffset-2)*n, pub_seed, node_addr, n); - - state->stacklevels[state->stackoffset-2]++; - state->stackoffset--; - } - state->next_leaf++; - return 0; -} - -/** - * Returns the auth path for node leaf_idx and computes the auth path for the - * next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo - * in "Post Quantum Cryptography", Springer 2009. - */ -static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int i; - unsigned int n = params->n; - unsigned int h = params->h; - unsigned int k = params->k; - - unsigned int tau = h; - unsigned int startidx; - unsigned int offset, rowidx; - unsigned char buf[2 * n]; - - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - for (i = 0; i < h; i++) { - if (! ((leaf_idx >> i) & 1)) { - tau = i; - break; - } - } - - if (tau > 0) { - memcpy(buf, state->auth + (tau-1) * n, n); - // we need to do this before refreshing state->keep to prevent overwriting - memcpy(buf + n, state->keep + ((tau-1) >> 1) * n, n); - } - if (!((leaf_idx >> (tau + 1)) & 1) && (tau < h - 1)) { - memcpy(state->keep + (tau >> 1)*n, state->auth + tau*n, n); - } - if (tau == 0) { - setLtreeADRS(ltree_addr, leaf_idx); - setOTSADRS(ots_addr, leaf_idx); - gen_leaf_wots(state->auth, sk_seed, params, pub_seed, ltree_addr, ots_addr); - } - else { - setTreeHeight(node_addr, (tau-1)); - setTreeIndex(node_addr, leaf_idx >> tau); - hash_h(state->auth + tau * n, buf, pub_seed, node_addr, n); - for (i = 0; i < tau; i++) { - if (i < h - k) { - memcpy(state->auth + i * n, state->treehash[i].node, n); - } - else { - offset = (1 << (h - 1 - i)) + i - h; - rowidx = ((leaf_idx >> i) - 1) >> 1; - memcpy(state->auth + i * n, state->retain + (offset + rowidx) * n, n); - } - } - - for (i = 0; i < ((tau < h - k) ? tau : (h - k)); i++) { - startidx = leaf_idx + 1 + 3 * (1 << i); - if (startidx < 1U << h) { - state->treehash[i].h = i; - state->treehash[i].next_idx = startidx; - state->treehash[i].completed = 0; - state->treehash[i].stackusage = 0; - } - } - } -} - -/* - * Generates a XMSS key pair for a given parameter set. - * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params) -{ - unsigned int n = params->n; - // Set idx = 0 - sk[0] = 0; - sk[1] = 0; - sk[2] = 0; - sk[3] = 0; - // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) - randombytes(sk+4, 3*n); - // Copy PUB_SEED to public key - memcpy(pk+n, sk+4+2*n, n); - - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Compute root - treehash_setup(pk, params->h, 0, state, sk+4, params, sk+4+2*n, addr); - // copy root to sk - memcpy(sk+4+3*n, pk, n); - return 0; -} - -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmss_params *params) -{ - unsigned int h = params->h; - unsigned int n = params->n; - unsigned int k = params->k; - uint16_t i = 0; - - // Extract SK - unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; - unsigned char sk_seed[n]; - memcpy(sk_seed, sk+4, n); - unsigned char sk_prf[n]; - memcpy(sk_prf, sk+4+n, n); - unsigned char pub_seed[n]; - memcpy(pub_seed, sk+4+2*n, n); - - // index as 32 bytes string - unsigned char idx_bytes_32[32]; - to_byte(idx_bytes_32, idx, 32); - - unsigned char hash_key[3*n]; - - // Update SK - sk[0] = ((idx + 1) >> 24) & 255; - sk[1] = ((idx + 1) >> 16) & 255; - sk[2] = ((idx + 1) >> 8) & 255; - sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - // Init working params - unsigned char R[n]; - unsigned char msg_h[n]; - unsigned char ots_seed[n]; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - prf(R, idx_bytes_32, sk_prf, n); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, n); - memcpy(hash_key+n, sk+4+3*n, n); - to_byte(hash_key+2*n, idx, n); - // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*n, n); - - // Start collecting signature - *sig_msg_len = 0; - - // Copy index to signature - sig_msg[0] = (idx >> 24) & 255; - sig_msg[1] = (idx >> 16) & 255; - sig_msg[2] = (idx >> 8) & 255; - sig_msg[3] = idx & 255; - - sig_msg += 4; - *sig_msg_len += 4; - - // Copy R to signature - for (i = 0; i < n; i++) - sig_msg[i] = R[i]; - - sig_msg += n; - *sig_msg_len += n; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Prepare Address - setType(ots_addr, 0); - setOTSADRS(ots_addr, idx); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, n, ots_addr); - - // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, &(params->wots_par), pub_seed, ots_addr); - - sig_msg += params->wots_par.keysize; - *sig_msg_len += params->wots_par.keysize; - - // the auth path was already computed during the previous round - memcpy(sig_msg, state->auth, h*n); - - if (idx < (1U << h) - 1) { - bds_round(state, idx, sk_seed, params, pub_seed, ots_addr); - bds_treehash_update(state, (h - k) >> 1, sk_seed, params, pub_seed, ots_addr); - } - -/* TODO: save key/bds state here! */ - - sig_msg += params->h*n; - *sig_msg_len += params->h*n; - - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); - - - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; - - return 0; -} - -/** - * Verifies a given message signature pair under a given public key. - */ -int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params) -{ - unsigned int n = params->n; - - unsigned long long i, m_len; - unsigned long idx=0; - unsigned char wots_pk[params->wots_par.keysize]; - unsigned char pkhash[n]; - unsigned char root[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - - unsigned char pub_seed[n]; - memcpy(pub_seed, pk+n, n); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - setType(ots_addr, 0); - setType(ltree_addr, 1); - setType(node_addr, 2); - - // Extract index - idx = ((unsigned long)sig_msg[0] << 24) | ((unsigned long)sig_msg[1] << 16) | ((unsigned long)sig_msg[2] << 8) | sig_msg[3]; - printf("verify:: idx = %lu\n", idx); - - // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg+4,n); - memcpy(hash_key+n, pk, n); - to_byte(hash_key+2*n, idx, n); - - sig_msg += (n+4); - sig_msg_len -= (n+4); - - // hash message - unsigned long long tmp_sig_len = params->wots_par.keysize+params->h*n; - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n); - - //----------------------- - // Verify signature - //----------------------- - - // Prepare Address - setOTSADRS(ots_addr, idx); - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->wots_par), pub_seed, ots_addr); - - sig_msg += params->wots_par.keysize; - sig_msg_len -= params->wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx); - l_tree(pkhash, wots_pk, params, pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx, sig_msg, params, pub_seed, node_addr); - - sig_msg += params->h*n; - sig_msg_len -= params->h*n; - - for (i = 0; i < n; i++) - if (root[i] != pk[i]) - goto fail; - - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = sig_msg[i]; - - return 0; - - -fail: - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; - return -1; -} - -/* - * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params) -{ - unsigned int n = params->n; - unsigned int i; - unsigned char ots_seed[params->n]; - // Set idx = 0 - for (i = 0; i < params->index_len; i++) { - sk[i] = 0; - } - // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) - randombytes(sk+params->index_len, 3*n); - // Copy PUB_SEED to public key - memcpy(pk+n, sk+params->index_len+2*n, n); - - // Set address to point on the single tree on layer d-1 - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - setLayerADRS(addr, (params->d-1)); - // Set up state and compute wots signatures for all but topmost tree root - for (i = 0; i < params->d - 1; i++) { - // Compute seed for OTS key pair - treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr); - setLayerADRS(addr, (i+1)); - get_seed(ots_seed, sk+params->index_len, n, addr); - wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, pk, ots_seed, &(params->xmss_par.wots_par), pk+n, addr); - } - treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr); - memcpy(sk+params->index_len+3*n, pk, n); - return 0; -} - -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params) -{ - unsigned int n = params->n; - - unsigned int tree_h = params->xmss_par.h; - unsigned int h = params->h; - unsigned int k = params->xmss_par.k; - unsigned int idx_len = params->index_len; - uint64_t idx_tree; - uint32_t idx_leaf; - uint64_t i, j; - int needswap_upto = -1; - unsigned int updates; - - unsigned char sk_seed[n]; - unsigned char sk_prf[n]; - unsigned char pub_seed[n]; - // Init working params - unsigned char R[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - unsigned char ots_seed[n]; - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char idx_bytes_32[32]; - bds_state tmp; - - // Extract SK - unsigned long long idx = 0; - for (i = 0; i < idx_len; i++) { - idx |= ((unsigned long long)sk[i]) << 8*(idx_len - 1 - i); - } - - memcpy(sk_seed, sk+idx_len, n); - memcpy(sk_prf, sk+idx_len+n, n); - memcpy(pub_seed, sk+idx_len+2*n, n); - - // Update SK - for (i = 0; i < idx_len; i++) { - sk[i] = ((idx + 1) >> 8*(idx_len - 1 - i)) & 255; - } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); - prf(R, idx_bytes_32, sk_prf, n); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, n); - memcpy(hash_key+n, sk+idx_len+3*n, n); - to_byte(hash_key+2*n, idx, n); - - // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*n, n); - - // Start collecting signature - *sig_msg_len = 0; - - // Copy index to signature - for (i = 0; i < idx_len; i++) { - sig_msg[i] = (idx >> 8*(idx_len - 1 - i)) & 255; - } - - sig_msg += idx_len; - *sig_msg_len += idx_len; - - // Copy R to signature - for (i = 0; i < n; i++) - sig_msg[i] = R[i]; - - sig_msg += n; - *sig_msg_len += n; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Handle lowest layer separately as it is slightly different... - - // Prepare Address - setType(ots_addr, 0); - idx_tree = idx >> tree_h; - idx_leaf = (idx & ((1 << tree_h)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setOTSADRS(ots_addr, idx_leaf); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, n, ots_addr); - - // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - *sig_msg_len += params->xmss_par.wots_par.keysize; - - memcpy(sig_msg, states[0].auth, tree_h*n); - sig_msg += tree_h*n; - *sig_msg_len += tree_h*n; - - // prepare signature of remaining layers - for (i = 1; i < params->d; i++) { - // put WOTS signature in place - memcpy(sig_msg, wots_sigs + (i-1)*params->xmss_par.wots_par.keysize, params->xmss_par.wots_par.keysize); - - sig_msg += params->xmss_par.wots_par.keysize; - *sig_msg_len += params->xmss_par.wots_par.keysize; - - // put AUTH nodes in place - memcpy(sig_msg, states[i].auth, tree_h*n); - sig_msg += tree_h*n; - *sig_msg_len += tree_h*n; - } - - updates = (tree_h - k) >> 1; - - setTreeADRS(addr, (idx_tree + 1)); - // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists - if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << h)) { - bds_state_update(&states[params->d], sk_seed, &(params->xmss_par), pub_seed, addr); - } - - for (i = 0; i < params->d; i++) { - // check if we're not at the end of a tree - if (! (((idx + 1) & ((1ULL << ((i+1)*tree_h)) - 1)) == 0)) { - idx_leaf = (idx >> (tree_h * i)) & ((1 << tree_h)-1); - idx_tree = (idx >> (tree_h * (i+1))); - setLayerADRS(addr, i); - setTreeADRS(addr, idx_tree); - if (i == (unsigned int) (needswap_upto + 1)) { - bds_round(&states[i], idx_leaf, sk_seed, &(params->xmss_par), pub_seed, addr); - } - updates = bds_treehash_update(&states[i], updates, sk_seed, &(params->xmss_par), pub_seed, addr); - setTreeADRS(addr, (idx_tree + 1)); - // if a NEXT-tree exists for this level; - if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << (h - tree_h * i))) { - if (i > 0 && updates > 0 && states[params->d + i].next_leaf < (1ULL << h)) { - bds_state_update(&states[params->d + i], sk_seed, &(params->xmss_par), pub_seed, addr); - updates--; - } - } - } - else if (idx < (1ULL << h) - 1) { - memcpy(&tmp, states+params->d + i, sizeof(bds_state)); - memcpy(states+params->d + i, states + i, sizeof(bds_state)); - memcpy(states + i, &tmp, sizeof(bds_state)); - - setLayerADRS(ots_addr, (i+1)); - setTreeADRS(ots_addr, ((idx + 1) >> ((i+2) * tree_h))); - setOTSADRS(ots_addr, (((idx >> ((i+1) * tree_h)) + 1) & ((1 << tree_h)-1))); - - get_seed(ots_seed, sk+params->index_len, n, ots_addr); - wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, states[i].stack, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - states[params->d + i].stackoffset = 0; - states[params->d + i].next_leaf = 0; - - updates--; // WOTS-signing counts as one update - needswap_upto = i; - for (j = 0; j < tree_h-k; j++) { - states[i].treehash[j].completed = 1; - } - } - } - - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); - - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; - - return 0; -} - -/** - * Verifies a given message signature pair under a given public key. - */ -int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params) -{ - unsigned int n = params->n; - - unsigned int tree_h = params->xmss_par.h; - unsigned int idx_len = params->index_len; - uint64_t idx_tree; - uint32_t idx_leaf; - - unsigned long long i, m_len; - unsigned long long idx=0; - unsigned char wots_pk[params->xmss_par.wots_par.keysize]; - unsigned char pkhash[n]; - unsigned char root[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - - unsigned char pub_seed[n]; - memcpy(pub_seed, pk+n, n); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Extract index - for (i = 0; i < idx_len; i++) { - idx |= ((unsigned long long)sig_msg[i]) << (8*(idx_len - 1 - i)); - } - printf("verify:: idx = %llu\n", idx); - sig_msg += idx_len; - sig_msg_len -= idx_len; - - // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg,n); - memcpy(hash_key+n, pk, n); - to_byte(hash_key+2*n, idx, n); - - sig_msg += n; - sig_msg_len -= n; - - - // hash message (recall, R is now on pole position at sig_msg - unsigned long long tmp_sig_len = (params->d * params->xmss_par.wots_par.keysize) + (params->h * n); - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n); - - - //----------------------- - // Verify signature - //----------------------- - - // Prepare Address - idx_tree = idx >> tree_h; - idx_leaf = (idx & ((1 << tree_h)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx_leaf); - - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - sig_msg_len -= params->xmss_par.wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx_leaf); - l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr); - - sig_msg += tree_h*n; - sig_msg_len -= tree_h*n; - - for (i = 1; i < params->d; i++) { - // Prepare Address - idx_leaf = (idx_tree & ((1 << tree_h)-1)); - idx_tree = idx_tree >> tree_h; - - setLayerADRS(ots_addr, i); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx_leaf); - - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, root, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - sig_msg_len -= params->xmss_par.wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx_leaf); - l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr); - - sig_msg += tree_h*n; - sig_msg_len -= tree_h*n; - - } - - for (i = 0; i < n; i++) - if (root[i] != pk[i]) - goto fail; - - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = sig_msg[i]; - - return 0; - - -fail: - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; - return -1; -} -#endif /* WITH_XMSS */ diff --git a/xmss_fast.h b/xmss_fast.h deleted file mode 100644 index 2ffba7057..000000000 --- a/xmss_fast.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_fast.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_fast.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "xmss_wots.h" - -#ifndef XMSS_H -#define XMSS_H -typedef struct{ - unsigned int level; - unsigned long long subtree; - unsigned int subleaf; -} leafaddr; - -typedef struct{ - wots_params wots_par; - unsigned int n; - unsigned int h; - unsigned int k; -} xmss_params; - -typedef struct{ - xmss_params xmss_par; - unsigned int n; - unsigned int h; - unsigned int d; - unsigned int index_len; -} xmssmt_params; - -typedef struct{ - unsigned int h; - unsigned int next_idx; - unsigned int stackusage; - unsigned char completed; - unsigned char *node; -} treehash_inst; - -typedef struct { - unsigned char *stack; - unsigned int stackoffset; - unsigned char *stacklevels; - unsigned char *auth; - unsigned char *keep; - treehash_inst *treehash; - unsigned char *retain; - unsigned int next_leaf; -} bds_state; - -/** - * Initialize BDS state struct - * parameter names are the same as used in the description of the BDS traversal - */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf); -/** - * Initializes parameter set. - * Needed, for any of the other methods. - */ -int xmss_set_params(xmss_params *params, int n, int h, int w, int k); -/** - * Initialize xmssmt_params struct - * parameter names are the same as in the draft - * - * Especially h is the total tree height, i.e. the XMSS trees have height h/d - */ -int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k); -/** - * Generates a XMSS key pair for a given parameter set. - * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params); -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg,unsigned long long msglen, const xmss_params *params); -/** - * Verifies a given message signature pair under a given public key. - * - * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). - */ -int xmss_sign_open(unsigned char *msg,unsigned long long *msglen, const unsigned char *sig_msg,unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params); - -/* - * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params); -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmssmt_sign(unsigned char *sk, bds_state *state, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params); -/** - * Verifies a given message signature pair under a given public key. - */ -int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params); -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_hash.c b/xmss_hash.c deleted file mode 100644 index 70c126ae2..000000000 --- a/xmss_hash.c +++ /dev/null @@ -1,137 +0,0 @@ -/* $OpenBSD: xmss_hash.c,v 1.4 2023/12/20 00:06:25 jsg Exp $ */ -/* -hash.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include "xmss_hash_address.h" -#include "xmss_commons.h" -#include "xmss_hash.h" - -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include -#include - -int core_hash_SHA2(unsigned char *, const unsigned int, const unsigned char *, - unsigned int, const unsigned char *, unsigned long long, unsigned int); - -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){ -#if IS_LITTLE_ENDIAN==1 - int i = 0; - for(i=0;i<8;i++) - to_byte(bytes+i*4, addr[i],4); - return bytes; -#else - memcpy(bytes, addr, 32); - return bytes; -#endif -} - -int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){ - unsigned long long i = 0; - unsigned char buf[inlen + n + keylen]; - - // Input is (toByte(X, 32) || KEY || M) - - // set toByte - to_byte(buf, type, n); - - for (i=0; i < keylen; i++) { - buf[i+n] = key[i]; - } - - for (i=0; i < inlen; i++) { - buf[keylen + n + i] = in[i]; - } - - if (n == 32) { - SHA256(buf, inlen + keylen + n, out); - return 0; - } - else { - if (n == 64) { - SHA512(buf, inlen + keylen + n, out); - return 0; - } - } - return 1; -} - -/** - * Implements PRF - */ -int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen) -{ - return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen); -} - -/* - * Implements H_msg - */ -int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n) -{ - if (keylen != 3*n){ - // H_msg takes 3n-bit keys, but n does not match the keylength of keylen - return -1; - } - return core_hash_SHA2(out, 2, key, keylen, in, inlen, n); -} - -/** - * We assume the left half is in in[0]...in[n-1] - */ -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) -{ - - unsigned char buf[2*n]; - unsigned char key[n]; - unsigned char bitmask[2*n]; - unsigned char byte_addr[32]; - unsigned int i; - - setKeyAndMask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); - // Use MSB order - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); - setKeyAndMask(addr, 2); - addr_to_byte(byte_addr, addr); - prf(bitmask+n, byte_addr, pub_seed, n); - for (i = 0; i < 2*n; i++) { - buf[i] = in[i] ^ bitmask[i]; - } - return core_hash_SHA2(out, 1, key, n, buf, 2*n, n); -} - -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) -{ - unsigned char buf[n]; - unsigned char key[n]; - unsigned char bitmask[n]; - unsigned char byte_addr[32]; - unsigned int i; - - setKeyAndMask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); - - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); - - for (i = 0; i < n; i++) { - buf[i] = in[i] ^ bitmask[i]; - } - return core_hash_SHA2(out, 0, key, n, buf, n, n); -} -#endif /* WITH_XMSS */ diff --git a/xmss_hash.h b/xmss_hash.h deleted file mode 100644 index d19c62152..000000000 --- a/xmss_hash.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_hash.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifndef HASH_H -#define HASH_H - -#define IS_LITTLE_ENDIAN 1 - -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]); -int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen); -int h_msg(unsigned char *out,const unsigned char *in,unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n); -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); - -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_hash_address.c b/xmss_hash_address.c deleted file mode 100644 index 2702c4562..000000000 --- a/xmss_hash_address.c +++ /dev/null @@ -1,66 +0,0 @@ -/* $OpenBSD: xmss_hash_address.c,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash_address.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ -#include "includes.h" -#ifdef WITH_XMSS - -#ifdef HAVE_STDINT_H -# include -#endif -#include "xmss_hash_address.h" /* prototypes */ - -void setLayerADRS(uint32_t adrs[8], uint32_t layer){ - adrs[0] = layer; -} - -void setTreeADRS(uint32_t adrs[8], uint64_t tree){ - adrs[1] = (uint32_t) (tree >> 32); - adrs[2] = (uint32_t) tree; -} - -void setType(uint32_t adrs[8], uint32_t type){ - adrs[3] = type; - int i; - for(i = 4; i < 8; i++){ - adrs[i] = 0; - } -} - -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask){ - adrs[7] = keyAndMask; -} - -// OTS - -void setOTSADRS(uint32_t adrs[8], uint32_t ots){ - adrs[4] = ots; -} - -void setChainADRS(uint32_t adrs[8], uint32_t chain){ - adrs[5] = chain; -} - -void setHashADRS(uint32_t adrs[8], uint32_t hash){ - adrs[6] = hash; -} - -// L-tree - -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree){ - adrs[4] = ltree; -} - -// Hash Tree & L-tree - -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight){ - adrs[5] = treeHeight; -} - -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex){ - adrs[6] = treeIndex; -} -#endif /* WITH_XMSS */ diff --git a/xmss_hash_address.h b/xmss_hash_address.h deleted file mode 100644 index 66bb4cc4d..000000000 --- a/xmss_hash_address.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_hash_address.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash_address.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifdef HAVE_STDINT_H -#include -#endif - -void setLayerADRS(uint32_t adrs[8], uint32_t layer); - -void setTreeADRS(uint32_t adrs[8], uint64_t tree); - -void setType(uint32_t adrs[8], uint32_t type); - -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask); - -// OTS - -void setOTSADRS(uint32_t adrs[8], uint32_t ots); - -void setChainADRS(uint32_t adrs[8], uint32_t chain); - -void setHashADRS(uint32_t adrs[8], uint32_t hash); - -// L-tree - -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree); - -// Hash Tree & L-tree - -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight); - -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex); - -#endif /* WITH_XMSS */ diff --git a/xmss_wots.c b/xmss_wots.c deleted file mode 100644 index 993e661f6..000000000 --- a/xmss_wots.c +++ /dev/null @@ -1,192 +0,0 @@ -/* $OpenBSD: xmss_wots.c,v 1.3 2018/04/10 00:10:49 djm Exp $ */ -/* -wots.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include -#include "xmss_commons.h" -#include "xmss_hash.h" -#include "xmss_wots.h" -#include "xmss_hash_address.h" - - -/* libm-free version of log2() for wots */ -static inline int -wots_log2(uint32_t v) -{ - int b; - - for (b = sizeof (v) * CHAR_BIT - 1; b >= 0; b--) { - if ((1U << b) & v) { - return b; - } - } - return 0; -} - -void -wots_set_params(wots_params *params, int n, int w) -{ - params->n = n; - params->w = w; - params->log_w = wots_log2(params->w); - params->len_1 = (CHAR_BIT * n) / params->log_w; - params->len_2 = (wots_log2(params->len_1 * (w - 1)) / params->log_w) + 1; - params->len = params->len_1 + params->len_2; - params->keysize = params->len * params->n; -} - -/** - * Helper method for pseudorandom key generation - * Expands an n-byte array into a len*n byte array - * this is done using PRF - */ -static void expand_seed(unsigned char *outseeds, const unsigned char *inseed, const wots_params *params) -{ - uint32_t i = 0; - unsigned char ctr[32]; - for(i = 0; i < params->len; i++){ - to_byte(ctr, i, 32); - prf((outseeds + (i*params->n)), ctr, inseed, params->n); - } -} - -/** - * Computes the chaining function. - * out and in have to be n-byte arrays - * - * interprets in as start-th value of the chain - * addr has to contain the address of the chain - */ -static void gen_chain(unsigned char *out, const unsigned char *in, unsigned int start, unsigned int steps, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - uint32_t i, j; - for (j = 0; j < params->n; j++) - out[j] = in[j]; - - for (i = start; i < (start+steps) && i < params->w; i++) { - setHashADRS(addr, i); - hash_f(out, out, pub_seed, addr, params->n); - } -} - -/** - * base_w algorithm as described in draft. - * - * - */ -static void base_w(int *output, const int out_len, const unsigned char *input, const wots_params *params) -{ - int in = 0; - int out = 0; - uint32_t total = 0; - int bits = 0; - int consumed = 0; - - for (consumed = 0; consumed < out_len; consumed++) { - if (bits == 0) { - total = input[in]; - in++; - bits += 8; - } - bits -= params->log_w; - output[out] = (total >> bits) & (params->w - 1); - out++; - } -} - -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - uint32_t i; - expand_seed(pk, sk, params); - for (i=0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*params->n, pk+i*params->n, 0, params->w-1, params, pub_seed, addr); - } -} - - -int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - //int basew[params->len]; - int csum = 0; - uint32_t i = 0; - int *basew = calloc(params->len, sizeof(int)); - if (basew == NULL) - return -1; - - base_w(basew, params->len_1, msg, params); - - for (i=0; i < params->len_1; i++) { - csum += params->w - 1 - basew[i]; - } - - csum = csum << (8 - ((params->len_2 * params->log_w) % 8)); - - int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8; - - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); - - int csum_basew[params->len_2]; - base_w(csum_basew, params->len_2, csum_bytes, params); - - for (i = 0; i < params->len_2; i++) { - basew[params->len_1 + i] = csum_basew[i]; - } - - expand_seed(sig, sk, params); - - for (i = 0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(sig+i*params->n, sig+i*params->n, 0, basew[i], params, pub_seed, addr); - } - free(basew); - return 0; -} - -int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - int csum = 0; - uint32_t i = 0; - int *basew = calloc(params->len, sizeof(int)); - if (basew == NULL) - return -1; - - base_w(basew, params->len_1, msg, params); - - for (i=0; i < params->len_1; i++) { - csum += params->w - 1 - basew[i]; - } - - csum = csum << (8 - ((params->len_2 * params->log_w) % 8)); - - int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8; - - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); - - int csum_basew[params->len_2]; - base_w(csum_basew, params->len_2, csum_bytes, params); - - for (i = 0; i < params->len_2; i++) { - basew[params->len_1 + i] = csum_basew[i]; - } - for (i=0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*params->n, sig+i*params->n, basew[i], params->w-1-basew[i], params, pub_seed, addr); - } - free(basew); - return 0; -} -#endif /* WITH_XMSS */ diff --git a/xmss_wots.h b/xmss_wots.h deleted file mode 100644 index 1eebf3b21..000000000 --- a/xmss_wots.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_wots.h,v 1.3 2018/02/26 12:14:53 dtucker Exp $ */ -/* -wots.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifndef WOTS_H -#define WOTS_H - -#ifdef HAVE_STDINT_H -#include "stdint.h" -#endif - -/** - * WOTS parameter set - * - * Meaning as defined in draft-irtf-cfrg-xmss-hash-based-signatures-02 - */ -typedef struct { - uint32_t len_1; - uint32_t len_2; - uint32_t len; - uint32_t n; - uint32_t w; - uint32_t log_w; - uint32_t keysize; -} wots_params; - -/** - * Set the WOTS parameters, - * only m, n, w are required as inputs, - * len, len_1, and len_2 are computed from those. - * - * Assumes w is a power of 2 - */ -void wots_set_params(wots_params *params, int n, int w); - -/** - * WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key. - * For this it takes the seed pub_seed which is used to generate bitmasks and hash keys and the address of this WOTS key pair addr - * - * params, must have been initialized before using wots_set params for params ! This is not done in this function - * - * Places the computed public key at address pk. - */ -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -/** - * Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig". - * - */ -int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -/** - * Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk. - * - */ -int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -#endif -#endif /* WITH_XMSS */