aboutsummaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
Diffstat (limited to 'regress')
-rw-r--r--regress/Makefile27
-rw-r--r--regress/addrmatch.sh14
-rw-r--r--regress/agent-getpeereid.sh14
-rw-r--r--regress/agent-pkcs11.sh12
-rw-r--r--regress/agent-subprocess.sh22
-rw-r--r--regress/agent.sh77
-rw-r--r--regress/allow-deny-users.sh8
-rw-r--r--regress/banner.sh6
-rw-r--r--regress/cert-hostkey.sh16
-rw-r--r--regress/cert-userkey.sh22
-rw-r--r--regress/cfginclude.sh24
-rw-r--r--regress/cfgmatch.sh8
-rw-r--r--regress/connect-privsep.sh5
-rw-r--r--regress/dhgex.sh4
-rw-r--r--regress/ed25519_openssh.prv7
-rw-r--r--regress/ed25519_openssh.pub1
-rw-r--r--regress/exit-status-signal.sh24
-rw-r--r--regress/forward-control.sh6
-rw-r--r--regress/forwarding.sh8
-rw-r--r--regress/hostkey-rotate.sh26
-rw-r--r--regress/key-options.sh2
-rw-r--r--regress/keygen-convert.sh60
-rw-r--r--regress/keygen-sshfp.sh29
-rw-r--r--regress/keys-command.sh4
-rw-r--r--regress/keytype.sh6
-rw-r--r--regress/knownhosts-command.sh55
-rw-r--r--regress/limit-keytype.sh18
-rw-r--r--regress/misc/Makefile2
-rw-r--r--regress/misc/fuzz-harness/Makefile46
-rw-r--r--regress/misc/fuzz-harness/agent_fuzz.cc15
-rw-r--r--regress/misc/fuzz-harness/agent_fuzz_helper.c177
-rw-r--r--regress/misc/fuzz-harness/fixed-keys.h119
-rw-r--r--regress/misc/fuzz-harness/kex_fuzz.cc461
-rw-r--r--regress/misc/fuzz-harness/testdata/README4
-rwxr-xr-xregress/misc/fuzz-harness/testdata/create-agent-corpus.sh44
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa21
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_dsa.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa8
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk14
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed255197
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519.pub2
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk8
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa27
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa-cert.pub1
-rw-r--r--regress/misc/fuzz-harness/testdata/id_rsa.pub1
-rw-r--r--regress/misc/kexfuzz/Makefile101
-rw-r--r--regress/misc/kexfuzz/README34
-rw-r--r--regress/misc/kexfuzz/kexfuzz.c453
-rw-r--r--regress/misc/sk-dummy/fatal.c11
-rw-r--r--regress/misc/sk-dummy/sk-dummy.c9
-rw-r--r--regress/multiplex.sh14
-rw-r--r--regress/multipubkey.sh19
-rw-r--r--regress/netcat.c41
-rw-r--r--regress/percent.sh53
-rw-r--r--regress/putty-ciphers.sh12
-rw-r--r--regress/putty-kex.sh12
-rw-r--r--regress/putty-transfer.sh12
-rw-r--r--regress/reconfigure.sh24
-rw-r--r--regress/rekey.sh8
-rw-r--r--regress/scp-uri.sh81
-rw-r--r--regress/scp.sh187
-rw-r--r--regress/scp3.sh60
-rw-r--r--regress/servcfginclude.sh44
-rw-r--r--regress/sftp-chroot.sh9
-rw-r--r--regress/sftp-perm.sh18
-rwxr-xr-xregress/ssh2putty.sh8
-rw-r--r--regress/sshcfgparse.sh39
-rw-r--r--regress/sshfp-connect.sh66
-rw-r--r--regress/sshsig.sh52
-rw-r--r--regress/test-exec.sh161
-rw-r--r--regress/unittests/Makefile4
-rw-r--r--regress/unittests/authopt/Makefile4
-rw-r--r--regress/unittests/authopt/tests.c10
-rw-r--r--regress/unittests/conversion/Makefile3
-rw-r--r--regress/unittests/conversion/tests.c34
-rw-r--r--regress/unittests/hostkeys/Makefile4
-rw-r--r--regress/unittests/hostkeys/test_iterate.c91
-rw-r--r--regress/unittests/kex/Makefile8
-rw-r--r--regress/unittests/kex/test_kex.c6
-rw-r--r--regress/unittests/match/Makefile4
-rw-r--r--regress/unittests/match/tests.c4
-rw-r--r--regress/unittests/misc/Makefile23
-rw-r--r--regress/unittests/misc/test_argv.c187
-rw-r--r--regress/unittests/misc/test_convtime.c59
-rw-r--r--regress/unittests/misc/test_expand.c90
-rw-r--r--regress/unittests/misc/test_parse.c86
-rw-r--r--regress/unittests/misc/test_strdelim.c202
-rw-r--r--regress/unittests/misc/tests.c77
-rw-r--r--regress/unittests/sshbuf/Makefile3
-rw-r--r--regress/unittests/sshkey/Makefile4
-rwxr-xr-xregress/unittests/sshkey/mktestdata.sh53
-rw-r--r--regress/unittests/sshkey/test_file.c133
-rw-r--r--regress/unittests/sshkey/test_fuzz.c4
-rw-r--r--regress/unittests/sshkey/test_sshkey.c9
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk113
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk1_pw14
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk213
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ecdsa_sk2.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk18
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1-cert.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1-cert.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1.pub1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk1_pw9
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk28
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk2.fp1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk2.fp.bb1
-rw-r--r--regress/unittests/sshkey/testdata/ed25519_sk2.pub1
-rw-r--r--regress/unittests/sshsig/Makefile25
-rwxr-xr-xregress/unittests/sshsig/mktestdata.sh42
-rw-r--r--regress/unittests/sshsig/testdata/dsa12
-rw-r--r--regress/unittests/sshsig/testdata/dsa.pub1
-rw-r--r--regress/unittests/sshsig/testdata/dsa.sig13
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa5
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa.pub1
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa.sig7
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa_sk13
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa_sk.pub1
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa_sk.sig8
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.pub1
-rw-r--r--regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.sig13
-rw-r--r--regress/unittests/sshsig/testdata/ed255197
-rw-r--r--regress/unittests/sshsig/testdata/ed25519.pub1
-rw-r--r--regress/unittests/sshsig/testdata/ed25519.sig6
-rw-r--r--regress/unittests/sshsig/testdata/ed25519_sk8
-rw-r--r--regress/unittests/sshsig/testdata/ed25519_sk.pub1
-rw-r--r--regress/unittests/sshsig/testdata/ed25519_sk.sig7
-rw-r--r--regress/unittests/sshsig/testdata/namespace1
-rw-r--r--regress/unittests/sshsig/testdata/rsa39
-rw-r--r--regress/unittests/sshsig/testdata/rsa.pub1
-rw-r--r--regress/unittests/sshsig/testdata/rsa.sig19
-rw-r--r--regress/unittests/sshsig/testdata/signed-data1
-rw-r--r--regress/unittests/sshsig/tests.c139
-rw-r--r--regress/unittests/sshsig/webauthn.html766
-rwxr-xr-xregress/valgrind-unit.sh2
151 files changed, 4181 insertions, 1141 deletions
diff --git a/regress/Makefile b/regress/Makefile
index 62794d25f..0b5ad45d7 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.108 2020/04/20 04:44:47 djm Exp $
+# $OpenBSD: Makefile,v 1.117 2021/09/03 04:11:13 dtucker Exp $
tests: prep file-tests t-exec unit
@@ -21,11 +21,13 @@ distclean: clean
LTESTS= connect \
proxy-connect \
+ sshfp-connect \
connect-privsep \
connect-uri \
proto-version \
proto-mismatch \
exit-status \
+ exit-status-signal \
envpass \
transfer \
banner \
@@ -41,12 +43,17 @@ LTESTS= connect \
agent-getpeereid \
agent-timeout \
agent-ptrace \
+ agent-subprocess \
keyscan \
keygen-change \
+ keygen-comment \
keygen-convert \
+ keygen-knownhosts \
keygen-moduli \
+ keygen-sshfp \
key-options \
scp \
+ scp3 \
scp-uri \
sftp \
sftp-chroot \
@@ -83,7 +90,6 @@ LTESTS= connect \
multipubkey \
limit-keytype \
hostkey-agent \
- keygen-knownhosts \
hostkey-rotate \
principals-command \
cert-file \
@@ -92,7 +98,7 @@ LTESTS= connect \
allow-deny-users \
authinfo \
sshsig \
- keygen-comment
+ knownhosts-command
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
@@ -113,7 +119,7 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \
host.ecdsa-sha2-nistp521 host.ssh-dss host.ssh-ed25519 \
host.ssh-rsa host_ca_key* host_krl_* host_revoked_* key.* \
key.dsa-* key.ecdsa-* key.ed25519-512 \
- key.ed25519-512.pub key.rsa-* keys-command-args kh.* \
+ key.ed25519-512.pub key.rsa-* keys-command-args kh.* askpass \
known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \
modpipe netcat no_identity_config \
pidfile putty.rsa2 ready regress.log remote_pid \
@@ -121,9 +127,9 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \
rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
- ssh-rsa_oldfmt \
+ ssh-rsa_oldfmt knownhosts_command \
ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
- ssh_proxy_envpass sshd.log sshd_config sshd_config_minimal \
+ ssh_proxy_* sshd.log sshd_config sshd_config.* \
sshd_config.* sshd_proxy sshd_proxy.* sshd_proxy_bak \
sshd_proxy_orig t10.out t10.out.pub t12.out t12.out.pub \
t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub \
@@ -247,15 +253,20 @@ unit:
V="" ; \
test "x${USE_VALGRIND}" = "x" || \
V=${.CURDIR}/valgrind-unit.sh ; \
- $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
- $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
+ $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
+ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
-d ${.CURDIR}/unittests/sshkey/testdata ; \
+ $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \
+ -d ${.CURDIR}/unittests/sshsig/testdata ; \
+ $$V ${.OBJDIR}/unittests/authopt/test_authopt \
+ -d ${.CURDIR}/unittests/authopt/testdata ; \
$$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \
$$V ${.OBJDIR}/unittests/conversion/test_conversion ; \
$$V ${.OBJDIR}/unittests/kex/test_kex ; \
$$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \
-d ${.CURDIR}/unittests/hostkeys/testdata ; \
$$V ${.OBJDIR}/unittests/match/test_match ; \
+ $$V ${.OBJDIR}/unittests/misc/test_misc ; \
if test "x${TEST_SSH_UTF8}" = "xyes" ; then \
$$V ${.OBJDIR}/unittests/utf8/test_utf8 ; \
fi \
diff --git a/regress/addrmatch.sh b/regress/addrmatch.sh
index e7d29c3f3..26e0c9910 100644
--- a/regress/addrmatch.sh
+++ b/regress/addrmatch.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: addrmatch.sh,v 1.5 2020/03/13 03:18:45 djm Exp $
+# $OpenBSD: addrmatch.sh,v 1.6 2020/08/28 03:17:13 dtucker Exp $
# Placed in the Public Domain.
tid="address match"
@@ -52,5 +52,17 @@ run_trial user ::5 somehost ::1 1234 match3 "IP6 localaddress"
run_trial user ::5 somehost ::2 5678 match4 "IP6 localport"
fi
+#
+# Check that we catch invalid address/mask in Match Address/Localaddress
+#
+for i in 10.0.1.0/8 10.0.0.1/24 2000:aa:bb:01::/56; do
+ for a in address localaddress; do
+ verbose "test invalid Match $a $i"
+ echo "Match $a $i" > $OBJ/sshd_proxy
+ ${SUDO} ${SSHD} -f $OBJ/sshd_proxy -t >/dev/null 2>&1 && \
+ fail "accepted invalid match $a $i"
+ done
+done
+
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
rm $OBJ/sshd_proxy_bak
diff --git a/regress/agent-getpeereid.sh b/regress/agent-getpeereid.sh
index 524340816..2874100fa 100644
--- a/regress/agent-getpeereid.sh
+++ b/regress/agent-getpeereid.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: agent-getpeereid.sh,v 1.11 2019/11/26 23:43:10 djm Exp $
+# $OpenBSD: agent-getpeereid.sh,v 1.13 2021/09/01 00:50:27 dtucker Exp $
# Placed in the Public Domain.
tid="disallow agent attach from other uid"
@@ -10,19 +10,15 @@ SSH_AUTH_SOCK=/nonexistent
if config_defined HAVE_GETPEEREID HAVE_GETPEERUCRED HAVE_SO_PEERCRED ; then
:
else
- echo "skipped (not supported on this platform)"
- exit 0
+ skip "skipped (not supported on this platform)"
fi
case "x$SUDO" in
xsudo) sudo=1;;
- xdoas) ;;
+ xdoas|xdoas\ *) ;;
x)
- echo "need SUDO to switch to uid $UNPRIV"
- echo SKIPPED
- exit 0 ;;
+ skip "need SUDO to switch to uid $UNPRIV" ;;
*)
- echo "unsupported $SUDO - "doas" and "sudo" are allowed"
- exit 0 ;;
+ skip "unsupported $SUDO - "doas" and "sudo" are allowed" ;;
esac
trace "start agent"
diff --git a/regress/agent-pkcs11.sh b/regress/agent-pkcs11.sh
index fbbaea518..268a70de8 100644
--- a/regress/agent-pkcs11.sh
+++ b/regress/agent-pkcs11.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: agent-pkcs11.sh,v 1.7 2019/11/26 23:43:10 djm Exp $
+# $OpenBSD: agent-pkcs11.sh,v 1.9 2021/07/25 12:13:03 dtucker Exp $
# Placed in the Public Domain.
tid="pkcs11 agent test"
@@ -62,16 +62,16 @@ notty() {
trace "generating keys"
RSA=${DIR}/RSA
EC=${DIR}/EC
-openssl genpkey -algorithm rsa > $RSA
-openssl pkcs8 -nocrypt -in $RSA |\
+$OPENSSL_BIN genpkey -algorithm rsa > $RSA
+$OPENSSL_BIN pkcs8 -nocrypt -in $RSA |\
softhsm2-util --slot "$slot" --label 01 --id 01 --pin "$TEST_SSH_PIN" --import /dev/stdin
-openssl genpkey \
+$OPENSSL_BIN genpkey \
-genparam \
-algorithm ec \
-pkeyopt ec_paramgen_curve:prime256v1 |\
- openssl genpkey \
+ $OPENSSL_BIN genpkey \
-paramfile /dev/stdin > $EC
-openssl pkcs8 -nocrypt -in $EC |\
+$OPENSSL_BIN pkcs8 -nocrypt -in $EC |\
softhsm2-util --slot "$slot" --label 02 --id 02 --pin "$TEST_SSH_PIN" --import /dev/stdin
trace "start agent"
diff --git a/regress/agent-subprocess.sh b/regress/agent-subprocess.sh
new file mode 100644
index 000000000..2f36d70cc
--- /dev/null
+++ b/regress/agent-subprocess.sh
@@ -0,0 +1,22 @@
+# $OpenBSD: agent-subprocess.sh,v 1.1 2020/06/19 05:07:09 dtucker Exp $
+# Placed in the Public Domain.
+
+tid="agent subprocess"
+
+trace "ensure agent exits when run as subprocess"
+${SSHAGENT} sh -c "echo \$SSH_AGENT_PID >$OBJ/pidfile; sleep 1"
+
+pid=`cat $OBJ/pidfile`
+
+# Currently ssh-agent polls every 10s so we need to wait at least that long.
+n=12
+while kill -0 $pid >/dev/null 2>&1 && test "$n" -gt "0"; do
+ n=$(($n - 1))
+ sleep 1
+done
+
+if test "$n" -eq "0"; then
+ fail "agent still running"
+fi
+
+rm -f $OBJ/pidfile
diff --git a/regress/agent.sh b/regress/agent.sh
index 39403653c..f187b6757 100644
--- a/regress/agent.sh
+++ b/regress/agent.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: agent.sh,v 1.17 2019/12/21 02:33:07 djm Exp $
+# $OpenBSD: agent.sh,v 1.20 2021/02/25 03:27:34 djm Exp $
# Placed in the Public Domain.
tid="simple agent test"
@@ -45,17 +45,20 @@ for t in ${SSH_KEYTYPES}; do
# add to authorized keys
cat $OBJ/$t-agent.pub >> $OBJ/authorized_keys_$USER
# add private key to agent
- ${SSHADD} $OBJ/$t-agent #> /dev/null 2>&1
+ ${SSHADD} $OBJ/$t-agent > /dev/null 2>&1
if [ $? -ne 0 ]; then
fail "ssh-add failed exit code $?"
fi
# add private key to second agent
- SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} $OBJ/$t-agent #> /dev/null 2>&1
+ SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} $OBJ/$t-agent > /dev/null 2>&1
if [ $? -ne 0 ]; then
fail "ssh-add failed exit code $?"
fi
- # Remove private key to ensure that we aren't accidentally using it.
- rm -f $OBJ/$t-agent
+ # Move private key to ensure that we aren't accidentally using it.
+ # Keep the corresponding public keys/certs around for later use.
+ mv -f $OBJ/$t-agent $OBJ/$t-agent-private
+ cp -f $OBJ/$t-agent.pub $OBJ/$t-agent-private.pub
+ cp -f $OBJ/$t-agent-cert.pub $OBJ/$t-agent-private-cert.pub
done
# Remove explicit identity directives from ssh_proxy
@@ -84,8 +87,8 @@ fi
for t in ${SSH_KEYTYPES}; do
trace "connect via agent using $t key"
if [ "$t" = "ssh-dss" ]; then
- echo "PubkeyAcceptedKeyTypes +ssh-dss" >> $OBJ/ssh_proxy
- echo "PubkeyAcceptedKeyTypes +ssh-dss" >> $OBJ/sshd_proxy
+ echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/ssh_proxy
+ echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/sshd_proxy
fi
${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub -oIdentitiesOnly=yes \
somehost exit 52
@@ -152,12 +155,72 @@ for t in ${SSH_KEYTYPES}; do
fi
done
+## Deletion tests.
+
trace "delete all agent keys"
${SSHADD} -D > /dev/null 2>&1
r=$?
if [ $r -ne 0 ]; then
fail "ssh-add -D failed: exit code $r"
fi
+# make sure they're gone
+${SSHADD} -l > /dev/null 2>&1
+r=$?
+if [ $r -ne 1 ]; then
+ fail "ssh-add -l returned unexpected exit code: $r"
+fi
+trace "readd keys"
+# re-add keys/certs to agent
+for t in ${SSH_KEYTYPES}; do
+ ${SSHADD} $OBJ/$t-agent-private >/dev/null 2>&1 || \
+ fail "ssh-add failed exit code $?"
+done
+# make sure they are there
+${SSHADD} -l > /dev/null 2>&1
+r=$?
+if [ $r -ne 0 ]; then
+ fail "ssh-add -l failed: exit code $r"
+fi
+
+check_key_absent() {
+ ${SSHADD} -L | grep "^$1 " >/dev/null
+ if [ $? -eq 0 ]; then
+ fail "$1 key unexpectedly present"
+ fi
+}
+check_key_present() {
+ ${SSHADD} -L | grep "^$1 " >/dev/null
+ if [ $? -ne 0 ]; then
+ fail "$1 key missing from agent"
+ fi
+}
+
+# delete the ed25519 key
+trace "delete single key by file"
+${SSHADD} -qdk $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed"
+check_key_absent ssh-ed25519
+check_key_present ssh-ed25519-cert-v01@openssh.com
+# Put key/cert back.
+${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \
+ fail "ssh-add failed exit code $?"
+check_key_present ssh-ed25519
+# Delete both key and certificate.
+trace "delete key/cert by file"
+${SSHADD} -qd $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed"
+check_key_absent ssh-ed25519
+check_key_absent ssh-ed25519-cert-v01@openssh.com
+# Put key/cert back.
+${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \
+ fail "ssh-add failed exit code $?"
+check_key_present ssh-ed25519
+# Delete certificate via stdin
+${SSHADD} -qd - < $OBJ/ssh-ed25519-agent-cert.pub || fail "ssh-add -d - failed"
+check_key_present ssh-ed25519
+check_key_absent ssh-ed25519-cert-v01@openssh.com
+# Delete key via stdin
+${SSHADD} -qd - < $OBJ/ssh-ed25519-agent.pub || fail "ssh-add -d - failed"
+check_key_absent ssh-ed25519
+check_key_absent ssh-ed25519-cert-v01@openssh.com
trace "kill agent"
${SSHAGENT} -k > /dev/null
diff --git a/regress/allow-deny-users.sh b/regress/allow-deny-users.sh
index 5c3895122..6c053eef0 100644
--- a/regress/allow-deny-users.sh
+++ b/regress/allow-deny-users.sh
@@ -1,6 +1,6 @@
# Public Domain
# Zev Weiss, 2016
-# $OpenBSD: allow-deny-users.sh,v 1.5 2018/07/13 02:13:50 djm Exp $
+# $OpenBSD: allow-deny-users.sh,v 1.6 2021/06/07 00:00:50 djm Exp $
tid="AllowUsers/DenyUsers"
@@ -20,10 +20,8 @@ test_auth()
failmsg="$4"
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
- echo DenyUsers="$deny" >> $OBJ/sshd_proxy
- echo AllowUsers="$allow" >> $OBJ/sshd_proxy
-
- start_sshd -oDenyUsers="$deny" -oAllowUsers="$allow"
+ test -z "$deny" || echo DenyUsers="$deny" >> $OBJ/sshd_proxy
+ test -z "$allow" || echo AllowUsers="$allow" >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy "$me@somehost" true
status=$?
diff --git a/regress/banner.sh b/regress/banner.sh
index 0d9654fe2..a84feb5ad 100644
--- a/regress/banner.sh
+++ b/regress/banner.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: banner.sh,v 1.3 2017/04/30 23:34:55 djm Exp $
+# $OpenBSD: banner.sh,v 1.4 2021/08/08 06:38:33 dtucker Exp $
# Placed in the Public Domain.
tid="banner"
@@ -37,7 +37,9 @@ done
trace "test suppress banner (-q)"
verbose "test $tid: suppress banner (-q)"
-( ${SSH} -q -F $OBJ/ssh_proxy otherhost true 2>$OBJ/banner.out && \
+# ssh-log-wrapper drops "-q" to preserve debug output so use ssh directly
+# for just this test.
+( ${REAL_SSH} -q -F $OBJ/ssh_proxy otherhost true 2>$OBJ/banner.out && \
cmp $OBJ/empty.in $OBJ/banner.out ) || \
fail "suppress banner (-q)"
diff --git a/regress/cert-hostkey.sh b/regress/cert-hostkey.sh
index 097bf8463..de8652b0e 100644
--- a/regress/cert-hostkey.sh
+++ b/regress/cert-hostkey.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: cert-hostkey.sh,v 1.23 2020/01/03 03:02:26 djm Exp $
+# $OpenBSD: cert-hostkey.sh,v 1.25 2021/06/08 22:30:27 djm Exp $
# Placed in the Public Domain.
tid="certified host keys"
@@ -29,12 +29,12 @@ for i in `$SSH -Q key | maybe_filter_sk`; do
done
(
echo "HostKeyAlgorithms ${types}"
- echo "PubkeyAcceptedKeyTypes *"
+ echo "PubkeyAcceptedAlgorithms *"
) >> $OBJ/ssh_proxy
cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
(
echo "HostKeyAlgorithms *"
- echo "PubkeyAcceptedKeyTypes *"
+ echo "PubkeyAcceptedAlgorithms *"
) >> $OBJ/sshd_proxy_bak
HOSTS='localhost-with-alias,127.0.0.1,::1'
@@ -283,11 +283,17 @@ for ktype in $PLAIN_TYPES ; do
) > $OBJ/sshd_proxy
${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
- -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
- -F $OBJ/ssh_proxy somehost true
+ -oGlobalKnownHostsFile=none -F $OBJ/ssh_proxy somehost true
if [ $? -ne 0 ]; then
fail "ssh cert connect failed"
fi
+ # Also check that it works when the known_hosts file is not in the
+ # first array position.
+ ${SSH} -oUserKnownHostsFile="/dev/null $OBJ/known_hosts-cert" \
+ -oGlobalKnownHostsFile=none -F $OBJ/ssh_proxy somehost true
+ if [ $? -ne 0 ]; then
+ fail "ssh cert connect failed known_hosts 2nd"
+ fi
done
# Wrong certificate
diff --git a/regress/cert-userkey.sh b/regress/cert-userkey.sh
index 91596fa78..baa6903ea 100644
--- a/regress/cert-userkey.sh
+++ b/regress/cert-userkey.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: cert-userkey.sh,v 1.25 2020/01/03 03:02:26 djm Exp $
+# $OpenBSD: cert-userkey.sh,v 1.26 2021/02/25 03:27:34 djm Exp $
# Placed in the Public Domain.
tid="certified user keys"
@@ -71,11 +71,11 @@ for ktype in $EXTRA_TYPES $PLAIN_TYPES ; do
echo "AuthorizedPrincipalsFile " \
"$OBJ/authorized_principals_%u"
echo "TrustedUserCAKeys $OBJ/user_ca_key.pub"
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
) > $OBJ/sshd_proxy
(
cat $OBJ/ssh_proxy_bak
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
) > $OBJ/ssh_proxy
# Missing authorized_principals
@@ -149,11 +149,11 @@ for ktype in $EXTRA_TYPES $PLAIN_TYPES ; do
(
cat $OBJ/sshd_proxy_bak
echo "UsePrivilegeSeparation $privsep"
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
) > $OBJ/sshd_proxy
(
cat $OBJ/ssh_proxy_bak
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
) > $OBJ/ssh_proxy
# Wrong principals list
@@ -204,12 +204,12 @@ basic_tests() {
(
cat $OBJ/sshd_proxy_bak
echo "UsePrivilegeSeparation $privsep"
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
echo "$extra_sshd"
) > $OBJ/sshd_proxy
(
cat $OBJ/ssh_proxy_bak
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
) > $OBJ/ssh_proxy
${SSH} -i $OBJ/cert_user_key_${ktype} \
@@ -224,7 +224,7 @@ basic_tests() {
cat $OBJ/sshd_proxy_bak
echo "UsePrivilegeSeparation $privsep"
echo "RevokedKeys $OBJ/cert_user_key_revoked"
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
echo "$extra_sshd"
) > $OBJ/sshd_proxy
cp $OBJ/cert_user_key_${ktype}.pub \
@@ -257,7 +257,7 @@ basic_tests() {
(
cat $OBJ/sshd_proxy_bak
echo "RevokedKeys $OBJ/user_ca_key.pub"
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
echo "$extra_sshd"
) > $OBJ/sshd_proxy
${SSH} -i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \
@@ -270,7 +270,7 @@ basic_tests() {
verbose "$tid: $auth CA does not authenticate"
(
cat $OBJ/sshd_proxy_bak
- echo "PubkeyAcceptedKeyTypes ${t}"
+ echo "PubkeyAcceptedAlgorithms ${t}"
echo "$extra_sshd"
) > $OBJ/sshd_proxy
verbose "$tid: ensure CA key does not authenticate user"
@@ -308,7 +308,7 @@ test_one() {
echo > $OBJ/authorized_keys_$USER
echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" \
>> $OBJ/sshd_proxy
- echo "PubkeyAcceptedKeyTypes ${t}*" \
+ echo "PubkeyAcceptedAlgorithms ${t}*" \
>> $OBJ/sshd_proxy
if test "x$auth_opt" != "x" ; then
echo $auth_opt >> $OBJ/sshd_proxy
diff --git a/regress/cfginclude.sh b/regress/cfginclude.sh
index 2fc39ce45..f5b492f17 100644
--- a/regress/cfginclude.sh
+++ b/regress/cfginclude.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: cfginclude.sh,v 1.2 2016/05/03 15:30:46 dtucker Exp $
+# $OpenBSD: cfginclude.sh,v 1.3 2021/06/08 06:52:43 djm Exp $
# Placed in the Public Domain.
tid="config include"
@@ -10,7 +10,7 @@ cat > $OBJ/ssh_config.i << _EOF
Match host a
Hostname aa
-Match host b
+Match host b # comment
Hostname bb
Include $OBJ/ssh_config.i.*
@@ -19,10 +19,10 @@ Match host c
Hostname cc
Match host m
- Include $OBJ/ssh_config.i.*
+ Include $OBJ/ssh_config.i.* # comment
Host d
- Hostname dd
+ Hostname dd # comment
Host e
Hostname ee
@@ -47,17 +47,17 @@ Match host a
Match host b
Hostname bbb
-Match host c
+Match host c # comment
Hostname ccc
-Host d
+Host d # comment
Hostname ddd
Host e
Hostname eee
Host f
- Hostname fff
+ Hostname fff # comment
_EOF
cat > $OBJ/ssh_config.i.2 << _EOF
@@ -142,7 +142,7 @@ trial a aa
# cleanup
rm -f $OBJ/ssh_config.i $OBJ/ssh_config.i.* $OBJ/ssh_config.out
-# $OpenBSD: cfginclude.sh,v 1.2 2016/05/03 15:30:46 dtucker Exp $
+# $OpenBSD: cfginclude.sh,v 1.3 2021/06/08 06:52:43 djm Exp $
# Placed in the Public Domain.
tid="config include"
@@ -185,11 +185,11 @@ cat > $OBJ/ssh_config.i.1 << _EOF
Match host a
Hostname aaa
-Match host b
+Match host b # comment
Hostname bbb
Match host c
- Hostname ccc
+ Hostname ccc # comment
Host d
Hostname ddd
@@ -220,8 +220,8 @@ Host e
Host f
Hostname ffff
-Match all
- Hostname xxxx
+Match all # comment
+ Hostname xxxx # comment
_EOF
trial() {
diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh
index 6620c84ed..05a666855 100644
--- a/regress/cfgmatch.sh
+++ b/regress/cfgmatch.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: cfgmatch.sh,v 1.12 2019/04/18 18:57:16 dtucker Exp $
+# $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $
# Placed in the Public Domain.
tid="sshd_config match"
@@ -39,16 +39,16 @@ stop_client()
}
cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
-echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_config
+echo "PermitOpen 127.0.0.1:1 # comment" >>$OBJ/sshd_config
echo "Match Address 127.0.0.1" >>$OBJ/sshd_config
echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_config
grep -v AuthorizedKeysFile $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy
-echo "AuthorizedKeysFile /dev/null" >>$OBJ/sshd_proxy
+echo "AuthorizedKeysFile /dev/null # comment" >>$OBJ/sshd_proxy
echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy
echo "Match user $USER" >>$OBJ/sshd_proxy
echo "AuthorizedKeysFile /dev/null $OBJ/authorized_keys_%u" >>$OBJ/sshd_proxy
-echo "Match Address 127.0.0.1" >>$OBJ/sshd_proxy
+echo "Match Address 127.0.0.1 # comment" >>$OBJ/sshd_proxy
echo "PermitOpen 127.0.0.1:2 127.0.0.1:3 127.0.0.1:$PORT" >>$OBJ/sshd_proxy
${SUDO} ${SSHD} -f $OBJ/sshd_config -T >/dev/null || \
diff --git a/regress/connect-privsep.sh b/regress/connect-privsep.sh
index b6abb65e3..8970340a2 100644
--- a/regress/connect-privsep.sh
+++ b/regress/connect-privsep.sh
@@ -16,13 +16,12 @@ echo 'UsePrivilegeSeparation sandbox' >> $OBJ/sshd_proxy
${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true
if [ $? -ne 0 ]; then
- # XXX replace this with fail once sandbox has stabilised
- warn "ssh privsep/sandbox+proxyconnect failed"
+ fail "ssh privsep/sandbox+proxyconnect failed"
fi
# Because sandbox is sensitive to changes in libc, especially malloc, retest
# with every malloc.conf option (and none).
-if [ -z "TEST_MALLOC_OPTIONS" ]; then
+if [ -z "$TEST_MALLOC_OPTIONS" ]; then
mopts="C F G J R S U X < >"
else
mopts=`echo $TEST_MALLOC_OPTIONS | sed 's/./& /g'`
diff --git a/regress/dhgex.sh b/regress/dhgex.sh
index ae64a9fb6..6dd4cfe3f 100644
--- a/regress/dhgex.sh
+++ b/regress/dhgex.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: dhgex.sh,v 1.6 2019/10/06 11:49:50 dtucker Exp $
+# $OpenBSD: dhgex.sh,v 1.7 2020/12/21 22:48:41 dtucker Exp $
# Placed in the Public Domain.
tid="dhgex"
@@ -58,4 +58,4 @@ check 3072 3des-cbc # 112 bits.
check 3072 `${SSH} -Q cipher | grep 128`
check 7680 `${SSH} -Q cipher | grep 192`
check 8192 `${SSH} -Q cipher | grep 256`
-check 8192 rijndael-cbc@lysator.liu.se chacha20-poly1305@openssh.com
+check 8192 chacha20-poly1305@openssh.com
diff --git a/regress/ed25519_openssh.prv b/regress/ed25519_openssh.prv
new file mode 100644
index 000000000..9f191b778
--- /dev/null
+++ b/regress/ed25519_openssh.prv
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACDE8/0FM7Yw6xc53QpiZUQAh/LK2mEAwNDNYdSR6GIGIwAAAKC+Cfdzvgn3
+cwAAAAtzc2gtZWQyNTUxOQAAACDE8/0FM7Yw6xc53QpiZUQAh/LK2mEAwNDNYdSR6GIGIw
+AAAEBm+60DgH0WMW7Z5oyvu1dxo7MaXe5RRMWTMJCfLkHexMTz/QUztjDrFzndCmJlRACH
+8sraYQDA0M1h1JHoYgYjAAAAGWR0dWNrZXJAcXVvbGwuZHR1Y2tlci5uZXQBAgME
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/ed25519_openssh.pub b/regress/ed25519_openssh.pub
new file mode 100644
index 000000000..910363138
--- /dev/null
+++ b/regress/ed25519_openssh.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMTz/QUztjDrFzndCmJlRACH8sraYQDA0M1h1JHoYgYj
diff --git a/regress/exit-status-signal.sh b/regress/exit-status-signal.sh
new file mode 100644
index 000000000..1b3af0d84
--- /dev/null
+++ b/regress/exit-status-signal.sh
@@ -0,0 +1,24 @@
+# This test performs validation that ssh client is not successive on being terminated
+
+tid="exit status on signal"
+
+# spawn client in background
+rm -f $OBJ/remote_pid
+${SSH} -F $OBJ/ssh_proxy somehost 'echo $$ >'$OBJ'/remote_pid; sleep 444' &
+ssh_pid=$!
+
+# wait for it to start
+n=20
+while [ ! -f $OBJ/remote_pid ] && [ $n -gt 0 ]; do
+ n=$(($n - 1))
+ sleep 1
+done
+
+kill $ssh_pid
+wait $ssh_pid
+exit_code=$?
+
+if [ $exit_code -eq 0 ]; then
+ fail "ssh client should fail on signal"
+fi
+
diff --git a/regress/forward-control.sh b/regress/forward-control.sh
index 3b1f69a71..02f7667a6 100644
--- a/regress/forward-control.sh
+++ b/regress/forward-control.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: forward-control.sh,v 1.7 2018/06/07 14:29:43 djm Exp $
+# $OpenBSD: forward-control.sh,v 1.8 2021/05/07 09:23:40 dtucker Exp $
# Placed in the Public Domain.
tid="sshd control of local and remote forwarding"
@@ -46,7 +46,7 @@ check_lfwd() {
wait_for_file_to_appear $READY || \
fatal "check_lfwd ssh fail: $_message"
${SSH} -F $OBJ/ssh_config -p $LFWD_PORT \
- -oConnectionAttempts=4 host true >/dev/null 2>&1
+ -oConnectionAttempts=10 host true >/dev/null 2>&1
_result=$?
kill $_sshpid `cat $READY` 2>/dev/null
wait_for_process_to_exit $_sshpid
@@ -76,7 +76,7 @@ check_rfwd() {
_result=$?
if test $_result -eq 0 ; then
${SSH} -F $OBJ/ssh_config -p $RFWD_PORT \
- -oConnectionAttempts=4 host true >/dev/null 2>&1
+ -oConnectionAttempts=10 host true >/dev/null 2>&1
_result=$?
kill $_sshpid `cat $READY` 2>/dev/null
wait_for_process_to_exit $_sshpid
diff --git a/regress/forwarding.sh b/regress/forwarding.sh
index cd634f2f6..a72bd3a05 100644
--- a/regress/forwarding.sh
+++ b/regress/forwarding.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: forwarding.sh,v 1.23 2019/07/20 09:50:58 dtucker Exp $
+# $OpenBSD: forwarding.sh,v 1.24 2021/05/07 09:23:40 dtucker Exp $
# Placed in the Public Domain.
tid="local and remote forwarding"
@@ -29,7 +29,7 @@ rm -f $CTL
${SSH} -S $CTL -N -M -F $OBJ/ssh_config -f $fwd somehost
trace "transfer over forwarded channels and check result"
-${SSH} -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \
+${SSH} -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=10' \
somehost cat ${DATA} > ${COPY}
test -s ${COPY} || fail "failed copy of ${DATA}"
cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
@@ -110,7 +110,7 @@ rm -f $CTL
${SSH} -S $CTL -N -M -F $OBJ/ssh_config -f somehost
trace "config file: transfer over forwarded channels and check result"
-${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=4' \
+${SSH} -F $OBJ/ssh_config -p${base}02 -o 'ConnectionAttempts=10' \
somehost cat ${DATA} > ${COPY}
test -s ${COPY} || fail "failed copy of ${DATA}"
cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
@@ -124,7 +124,7 @@ ${SSH} -S $CTL -N -M -f -F $OBJ/ssh_config -R${base}01:[$OBJ/unix-1.fwd] somehos
${SSH} -S $CTL.1 -N -M -f -F $OBJ/ssh_config -L[$OBJ/unix-1.fwd]:[$OBJ/unix-2.fwd] somehost
${SSH} -S $CTL.2 -N -M -f -F $OBJ/ssh_config -R[$OBJ/unix-2.fwd]:[$OBJ/unix-3.fwd] somehost
${SSH} -S $CTL.3 -N -M -f -F $OBJ/ssh_config -L[$OBJ/unix-3.fwd]:127.0.0.1:$PORT somehost
-${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=4' \
+${SSH} -F $OBJ/ssh_config -p${base}01 -o 'ConnectionAttempts=10' \
somehost cat ${DATA} > ${COPY}
test -s ${COPY} || fail "failed copy ${DATA}"
cmp ${DATA} ${COPY} || fail "corrupted copy of ${DATA}"
diff --git a/regress/hostkey-rotate.sh b/regress/hostkey-rotate.sh
index c3e100c3e..0ae0c3dfc 100644
--- a/regress/hostkey-rotate.sh
+++ b/regress/hostkey-rotate.sh
@@ -1,12 +1,34 @@
-# $OpenBSD: hostkey-rotate.sh,v 1.8 2019/11/26 23:43:10 djm Exp $
+# $OpenBSD: hostkey-rotate.sh,v 1.9 2020/10/07 06:38:16 djm Exp $
# Placed in the Public Domain.
tid="hostkey rotate"
-rm -f $OBJ/hkr.* $OBJ/ssh_proxy.orig
+#
+# GNU (f)grep <=2.18, as shipped by FreeBSD<=12 and NetBSD<=9 will occasionally
+# fail to find ssh host keys in the hostkey-rotate test. If we have those
+# versions, use awk instead.
+# See # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=258616
+#
+case `grep --version 2>&1 | awk '/GNU grep/{print $4}'` in
+2.19) fgrep=good ;;
+1.*|2.?|2.?.?|2.1?) fgrep=bad ;; # stock GNU grep
+2.5.1*) fgrep=bad ;; # FreeBSD and NetBSD
+*) fgrep=good ;;
+esac
+if test "x$fgrep" = "xbad"; then
+ fgrep()
+{
+ awk 'BEGIN{e=1} {if (index($0,"'$1'")>0){e=0;print}} END{exit e}' $2
+}
+fi
+
+rm -f $OBJ/hkr.* $OBJ/ssh_proxy.orig $OBJ/ssh_proxy.orig
grep -vi 'hostkey' $OBJ/sshd_proxy > $OBJ/sshd_proxy.orig
+mv $OBJ/ssh_proxy $OBJ/ssh_proxy.orig
+grep -vi 'globalknownhostsfile' $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy
echo "UpdateHostkeys=yes" >> $OBJ/ssh_proxy
+echo "GlobalKnownHostsFile=none" >> $OBJ/ssh_proxy
rm $OBJ/known_hosts
# The "primary" key type is ed25519 since it's supported even when built
diff --git a/regress/key-options.sh b/regress/key-options.sh
index 097f46eba..2f3d66e2e 100644
--- a/regress/key-options.sh
+++ b/regress/key-options.sh
@@ -9,7 +9,7 @@ cp $authkeys $origkeys
# Allocating ptys can require privileges on some platforms.
skip_pty=""
-if ! config_defined HAVE_OPENPTY && [ "x$SUDO" == "x" ]; then
+if ! config_defined HAVE_OPENPTY && [ "x$SUDO" = "x" ]; then
skip_pty="no openpty(3) and SUDO not set"
fi
diff --git a/regress/keygen-convert.sh b/regress/keygen-convert.sh
index fce110ea1..95656581c 100644
--- a/regress/keygen-convert.sh
+++ b/regress/keygen-convert.sh
@@ -1,40 +1,54 @@
-# $OpenBSD: keygen-convert.sh,v 1.2 2019/07/23 07:55:29 dtucker Exp $
+# $OpenBSD: keygen-convert.sh,v 1.6 2021/07/24 02:57:28 dtucker Exp $
# Placed in the Public Domain.
tid="convert keys"
-types=""
-for i in ${SSH_KEYTYPES}; do
- case "$i" in
- ssh-dss) types="$types dsa" ;;
- ssh-rsa) types="$types rsa" ;;
- esac
-done
+cat > $OBJ/askpass <<EOD
+#!/bin/sh
+echo hunter2
+EOD
+chmod u+x $OBJ/askpass
+
+if ${SSHKEYGEN} -? 2>&1 | grep "ssh-keygen -e" >/dev/null; then
+ test_import_export=1
+fi
-for t in $types; do
+for t in ${SSH_KEYTYPES}; do
# generate user key for agent
trace "generating $t key"
rm -f $OBJ/$t-key
${SSHKEYGEN} -q -N "" -t $t -f $OBJ/$t-key
- trace "export $t private to rfc4716 public"
- ${SSHKEYGEN} -q -e -f $OBJ/$t-key >$OBJ/$t-key-rfc || \
- fail "export $t private to rfc4716 public"
+ if test "x$test_import_export" = "x1"; then
+ trace "export $t private to rfc4716 public"
+ ${SSHKEYGEN} -q -e -f $OBJ/$t-key >$OBJ/$t-key-rfc || \
+ fail "export $t private to rfc4716 public"
+
+ trace "export $t public to rfc4716 public"
+ ${SSHKEYGEN} -q -e -f $OBJ/$t-key.pub >$OBJ/$t-key-rfc.pub || \
+ fail "$t public to rfc4716 public"
+
+ cmp $OBJ/$t-key-rfc $OBJ/$t-key-rfc.pub || \
+ fail "$t rfc4716 exports differ between public and private"
- trace "export $t public to rfc4716 public"
- ${SSHKEYGEN} -q -e -f $OBJ/$t-key.pub >$OBJ/$t-key-rfc.pub || \
- fail "$t public to rfc4716 public"
+ trace "import $t rfc4716 public"
+ ${SSHKEYGEN} -q -i -f $OBJ/$t-key-rfc >$OBJ/$t-rfc-imported || \
+ fail "$t import rfc4716 public"
- cmp $OBJ/$t-key-rfc $OBJ/$t-key-rfc.pub || \
- fail "$t rfc4716 exports differ between public and private"
+ cut -f1,2 -d " " $OBJ/$t-key.pub >$OBJ/$t-key-nocomment.pub
+ cmp $OBJ/$t-key-nocomment.pub $OBJ/$t-rfc-imported || \
+ fail "$t imported differs from original"
+ fi
- trace "import $t rfc4716 public"
- ${SSHKEYGEN} -q -i -f $OBJ/$t-key-rfc >$OBJ/$t-rfc-imported || \
- fail "$t import rfc4716 public"
+ trace "set passphrase $t"
+ ${SSHKEYGEN} -q -p -P '' -N 'hunter2' -f $OBJ/$t-key >/dev/null || \
+ fail "$t set passphrase failed"
- cut -f1,2 -d " " $OBJ/$t-key.pub >$OBJ/$t-key-nocomment.pub
- cmp $OBJ/$t-key-nocomment.pub $OBJ/$t-rfc-imported || \
- fail "$t imported differs from original"
+ trace "export $t to public with passphrase"
+ SSH_ASKPASS=$OBJ/askpass SSH_ASKPASS_REQUIRE=force \
+ ${SSHKEYGEN} -y -f $OBJ/$t-key >$OBJ/$t-key-nocomment.pub
+ cmp $OBJ/$t-key.pub $OBJ/$t-key-nocomment.pub || \
+ fail "$t exported pubkey differs from generated"
rm -f $OBJ/$t-key $OBJ/$t-key.pub $OBJ/$t-key-rfc $OBJ/$t-key-rfc.pub \
$OBJ/$t-rfc-imported $OBJ/$t-key-nocomment.pub
diff --git a/regress/keygen-sshfp.sh b/regress/keygen-sshfp.sh
new file mode 100644
index 000000000..2abf9adec
--- /dev/null
+++ b/regress/keygen-sshfp.sh
@@ -0,0 +1,29 @@
+# $OpenBSD: keygen-sshfp.sh,v 1.2 2021/07/19 02:29:28 dtucker Exp $
+# Placed in the Public Domain.
+
+tid="keygen-sshfp"
+
+trace "keygen fingerprints"
+fp=`${SSHKEYGEN} -r test -f ${SRC}/ed25519_openssh.pub | \
+ awk '$5=="1"{print $6}'`
+if [ "$fp" != "8a8647a7567e202ce317e62606c799c53d4c121f" ]; then
+ fail "keygen fingerprint sha1"
+fi
+fp=`${SSHKEYGEN} -r test -f ${SRC}/ed25519_openssh.pub | \
+ awk '$5=="2"{print $6}'`
+if [ "$fp" != \
+ "54a506fb849aafb9f229cf78a94436c281efcb4ae67c8a430e8c06afcb5ee18f" ]; then
+ fail "keygen fingerprint sha256"
+fi
+
+if ${SSH} -Q key-plain | grep ssh-rsa >/dev/null; then
+ fp=`${SSHKEYGEN} -r test -f ${SRC}/rsa_openssh.pub | awk '$5=="1"{print $6}'`
+ if [ "$fp" != "99c79cc09f5f81069cc017cdf9552cfc94b3b929" ]; then
+ fail "keygen fingerprint sha1"
+ fi
+ fp=`${SSHKEYGEN} -r test -f ${SRC}/rsa_openssh.pub | awk '$5=="2"{print $6}'`
+ if [ "$fp" != \
+ "e30d6b9eb7a4de495324e4d5870b8220577993ea6af417e8e4a4f1c5bf01a9b6" ]; then
+ fail "keygen fingerprint sha256"
+ fi
+fi
diff --git a/regress/keys-command.sh b/regress/keys-command.sh
index 33b6e7b42..a3acf5e4d 100644
--- a/regress/keys-command.sh
+++ b/regress/keys-command.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: keys-command.sh,v 1.6 2019/07/25 08:48:11 dtucker Exp $
+# $OpenBSD: keys-command.sh,v 1.7 2021/09/01 00:50:27 dtucker Exp $
# Placed in the Public Domain.
tid="authorized keys from command"
@@ -77,5 +77,5 @@ if [ -x $KEY_COMMAND ]; then
fail "connect failed"
fi
else
- echo "SKIPPED: $KEY_COMMAND not executable (/var/run mounted noexec?)"
+ skip "$KEY_COMMAND not executable (/var/run mounted noexec?)"
fi
diff --git a/regress/keytype.sh b/regress/keytype.sh
index 20a8ceaf2..f1c045183 100644
--- a/regress/keytype.sh
+++ b/regress/keytype.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: keytype.sh,v 1.10 2019/12/16 02:39:05 djm Exp $
+# $OpenBSD: keytype.sh,v 1.11 2021/02/25 03:27:34 djm Exp $
# Placed in the Public Domain.
tid="login with different key types"
@@ -58,13 +58,13 @@ for ut in $ktypes; do
(
grep -v HostKey $OBJ/sshd_proxy_bak
echo HostKey $OBJ/key.$ht
- echo PubkeyAcceptedKeyTypes $user_type
+ echo PubkeyAcceptedAlgorithms $user_type
echo HostKeyAlgorithms $host_type
) > $OBJ/sshd_proxy
(
grep -v IdentityFile $OBJ/ssh_proxy_bak
echo IdentityFile $OBJ/key.$ut
- echo PubkeyAcceptedKeyTypes $user_type
+ echo PubkeyAcceptedAlgorithms $user_type
echo HostKeyAlgorithms $host_type
) > $OBJ/ssh_proxy
(
diff --git a/regress/knownhosts-command.sh b/regress/knownhosts-command.sh
new file mode 100644
index 000000000..8472ec812
--- /dev/null
+++ b/regress/knownhosts-command.sh
@@ -0,0 +1,55 @@
+# $OpenBSD: knownhosts-command.sh,v 1.3 2021/08/30 01:15:45 djm Exp $
+# Placed in the Public Domain.
+
+tid="known hosts command "
+
+rm -f $OBJ/knownhosts_command $OBJ/ssh_proxy_khc
+cp $OBJ/ssh_proxy $OBJ/ssh_proxy_orig
+
+( grep -vi GlobalKnownHostsFile $OBJ/ssh_proxy_orig | \
+ grep -vi UserKnownHostsFile;
+ echo "GlobalKnownHostsFile none" ;
+ echo "UserKnownHostsFile none" ;
+ echo "KnownHostsCommand $OBJ/knownhosts_command '%t' '%K' '%u'" ;
+) > $OBJ/ssh_proxy
+
+verbose "simple connection"
+cat > $OBJ/knownhosts_command << _EOF
+#!/bin/sh
+cat $OBJ/known_hosts
+_EOF
+chmod a+x $OBJ/knownhosts_command
+${SSH} -F $OBJ/ssh_proxy x true || fail "ssh connect failed"
+
+verbose "no keys"
+cat > $OBJ/knownhosts_command << _EOF
+#!/bin/sh
+exit 0
+_EOF
+chmod a+x $OBJ/knownhosts_command
+${SSH} -F $OBJ/ssh_proxy x true && fail "ssh connect succeeded with no keys"
+
+verbose "bad exit status"
+cat > $OBJ/knownhosts_command << _EOF
+#!/bin/sh
+cat $OBJ/known_hosts
+exit 1
+_EOF
+chmod a+x $OBJ/knownhosts_command
+${SSH} -F $OBJ/ssh_proxy x true && fail "ssh connect succeeded with bad exit"
+
+for keytype in ${SSH_HOSTKEY_TYPES} ; do
+ algs=$keytype
+ test "x$keytype" = "xssh-dss" && continue
+ test "x$keytype" = "xssh-rsa" && algs=ssh-rsa,rsa-sha2-256,rsa-sha2-512
+ verbose "keytype $keytype"
+ cat > $OBJ/knownhosts_command << _EOF
+#!/bin/sh
+die() { echo "\$@" 1>&2 ; exit 1; }
+test "x\$1" = "x$keytype" || die "wrong keytype \$1 (expected $keytype)"
+test "x\$3" = "x$LOGNAME" || die "wrong username \$3 (expected $LOGNAME)"
+grep -- "\$1.*\$2" $OBJ/known_hosts
+_EOF
+ ${SSH} -F $OBJ/ssh_proxy -oHostKeyAlgorithms=$algs x true ||
+ fail "ssh connect failed for keytype $x"
+done
diff --git a/regress/limit-keytype.sh b/regress/limit-keytype.sh
index 010a88cd7..7127de007 100644
--- a/regress/limit-keytype.sh
+++ b/regress/limit-keytype.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: limit-keytype.sh,v 1.9 2019/12/16 02:39:05 djm Exp $
+# $OpenBSD: limit-keytype.sh,v 1.10 2021/02/25 03:27:34 djm Exp $
# Placed in the Public Domain.
tid="restrict pubkey type"
@@ -69,7 +69,7 @@ prepare_config() {
) > $OBJ/sshd_proxy
}
-# Return the required parameter for PubkeyAcceptedKeyTypes corresponding to
+# Return the required parameter for PubkeyAcceptedAlgorithms corresponding to
# the supplied key type.
keytype() {
case "$1" in
@@ -92,14 +92,14 @@ ${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed"
# Allow plain Ed25519 and RSA. The certificate should fail.
verbose "allow $ktype2,$ktype1"
prepare_config \
- "PubkeyAcceptedKeyTypes `keytype $ktype2`,`keytype $ktype1`"
+ "PubkeyAcceptedAlgorithms `keytype $ktype2`,`keytype $ktype1`"
${SSH} $certopts proxy true && fatal "cert succeeded"
${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed"
${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed"
# Allow Ed25519 only.
verbose "allow $ktype1"
-prepare_config "PubkeyAcceptedKeyTypes `keytype $ktype1`"
+prepare_config "PubkeyAcceptedAlgorithms `keytype $ktype1`"
${SSH} $certopts proxy true && fatal "cert succeeded"
${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed"
if [ "$ktype1" != "$ktype2" ]; then
@@ -108,15 +108,15 @@ fi
# Allow all certs. Plain keys should fail.
verbose "allow cert only"
-prepare_config "PubkeyAcceptedKeyTypes *-cert-v01@openssh.com"
+prepare_config "PubkeyAcceptedAlgorithms *-cert-v01@openssh.com"
${SSH} $certopts proxy true || fatal "cert failed"
${SSH} $opts -i $OBJ/user_key1 proxy true && fatal "key1 succeeded"
${SSH} $opts -i $OBJ/user_key2 proxy true && fatal "key2 succeeded"
# Allow RSA in main config, Ed25519 for non-existent user.
verbose "match w/ no match"
-prepare_config "PubkeyAcceptedKeyTypes `keytype $ktype2`" \
- "Match user x$USER" "PubkeyAcceptedKeyTypes +`keytype $ktype1`"
+prepare_config "PubkeyAcceptedAlgorithms `keytype $ktype2`" \
+ "Match user x$USER" "PubkeyAcceptedAlgorithms +`keytype $ktype1`"
${SSH} $certopts proxy true && fatal "cert succeeded"
if [ "$ktype1" != "$ktype2" ]; then
${SSH} $opts -i $OBJ/user_key1 proxy true && fatal "key1 succeeded"
@@ -125,8 +125,8 @@ ${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed"
# Allow only DSA in main config, Ed25519 for user.
verbose "match w/ matching"
-prepare_config "PubkeyAcceptedKeyTypes `keytype $ktype4`" \
- "Match user $USER" "PubkeyAcceptedKeyTypes +`keytype $ktype1`"
+prepare_config "PubkeyAcceptedAlgorithms `keytype $ktype4`" \
+ "Match user $USER" "PubkeyAcceptedAlgorithms +`keytype $ktype1`"
${SSH} $certopts proxy true || fatal "cert failed"
${SSH} $opts -i $OBJ/user_key1 proxy true || fatal "key1 failed"
${SSH} $opts -i $OBJ/user_key4 proxy true && fatal "key4 succeeded"
diff --git a/regress/misc/Makefile b/regress/misc/Makefile
index cf95f265c..b9149f287 100644
--- a/regress/misc/Makefile
+++ b/regress/misc/Makefile
@@ -1,3 +1,3 @@
-SUBDIR= kexfuzz sk-dummy
+SUBDIR= sk-dummy
.include <bsd.subdir.mk>
diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile
index 64fbdbab1..e879fcdae 100644
--- a/regress/misc/fuzz-harness/Makefile
+++ b/regress/misc/fuzz-harness/Makefile
@@ -1,38 +1,52 @@
# NB. libssh and libopenbsd-compat should be built with the same sanitizer opts.
-CXX=clang++-6.0
-FUZZ_FLAGS=-fsanitize=address,undefined -fsanitize-coverage=edge,trace-pc
+CC=clang-11
+CXX=clang++-11
+FUZZ_FLAGS=-fsanitize=address,fuzzer -fno-omit-frame-pointer
FUZZ_LIBS=-lFuzzer
CXXFLAGS=-O2 -g -Wall -Wextra -Wno-unused-parameter -I ../../.. $(FUZZ_FLAGS)
+CFLAGS=$(CXXFLAGS)
LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g $(FUZZ_FLAGS)
LIBS=-lssh -lopenbsd-compat -lcrypto -lfido2 -lcbor $(FUZZ_LIBS)
-COMMON_OBJS=ssh-sk-null.o
+SK_NULL_OBJS=ssh-sk-null.o
+COMMON_DEPS=../../../libssh.a
TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz sshsig_fuzz \
- sshsigopt_fuzz privkey_fuzz
+ sshsigopt_fuzz privkey_fuzz kex_fuzz agent_fuzz
all: $(TARGETS)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
-pubkey_fuzz: pubkey_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ pubkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+pubkey_fuzz: pubkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ pubkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
-sig_fuzz: sig_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sig_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+sig_fuzz: sig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sig_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
-authopt_fuzz: authopt_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ authopt_fuzz.o $(COMMON_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
+authopt_fuzz: authopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ authopt_fuzz.o $(SK_NULL_OBJS) ../../../auth-options.o $(LDFLAGS) $(LIBS)
-sshsig_fuzz: sshsig_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sshsig_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
+sshsig_fuzz: sshsig_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sshsig_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
-sshsigopt_fuzz: sshsigopt_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ sshsigopt_fuzz.o $(COMMON_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
+sshsigopt_fuzz: sshsigopt_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ sshsigopt_fuzz.o $(SK_NULL_OBJS) ../../../sshsig.o $(LDFLAGS) $(LIBS)
-privkey_fuzz: privkey_fuzz.o $(COMMON_OBJS)
- $(CXX) -o $@ privkey_fuzz.o $(COMMON_OBJS) $(LDFLAGS) $(LIBS)
+privkey_fuzz: privkey_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ privkey_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS)
+
+kex_fuzz: kex_fuzz.o $(SK_NULL_OBJS) $(COMMON_DEPS)
+ $(CXX) -o $@ kex_fuzz.o $(SK_NULL_OBJS) $(LDFLAGS) $(LIBS) -lz
+
+agent_fuzz: agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(COMMON_DEPS)
+ $(CXX) -o $@ agent_fuzz.o agent_fuzz_helper.o sk-dummy.o ../../../ssh-sk.o $(LDFLAGS) $(LIBS) -lz
+
+agent_fuzz_helper.o: agent_fuzz_helper.c ../../../ssh-agent.c
+
+sk-dummy.o: ../sk-dummy/sk-dummy.c
+ $(CC) $(CFLAGS) -c -o $@ ../sk-dummy/sk-dummy.c -DSK_DUMMY_INTEGRATE=1 $(LDFLAGS)
clean:
-rm -f *.o $(TARGETS)
diff --git a/regress/misc/fuzz-harness/agent_fuzz.cc b/regress/misc/fuzz-harness/agent_fuzz.cc
new file mode 100644
index 000000000..ad85b2f9a
--- /dev/null
+++ b/regress/misc/fuzz-harness/agent_fuzz.cc
@@ -0,0 +1,15 @@
+// cc_fuzz_target test for ssh-agent.
+extern "C" {
+
+#include <stdint.h>
+#include <sys/types.h>
+
+extern void test_one(const uint8_t* s, size_t slen);
+
+int LLVMFuzzerTestOneInput(const uint8_t* s, size_t slen)
+{
+ test_one(s, slen);
+ return 0;
+}
+
+} // extern
diff --git a/regress/misc/fuzz-harness/agent_fuzz_helper.c b/regress/misc/fuzz-harness/agent_fuzz_helper.c
new file mode 100644
index 000000000..1d419820c
--- /dev/null
+++ b/regress/misc/fuzz-harness/agent_fuzz_helper.c
@@ -0,0 +1,177 @@
+#include "fixed-keys.h"
+#include <assert.h>
+
+#define main(ac, av) xxxmain(ac, av)
+#include "../../../ssh-agent.c"
+
+void test_one(const uint8_t* s, size_t slen);
+
+static int
+devnull_or_die(void)
+{
+ int fd;
+
+ if ((fd = open("/dev/null", O_RDWR)) == -1) {
+ error_f("open /dev/null: %s", strerror(errno));
+ abort();
+ }
+ return fd;
+}
+
+static struct sshkey *
+pubkey_or_die(const char *s)
+{
+ char *tmp, *cp;
+ struct sshkey *pubkey;
+ int r;
+
+ tmp = cp = xstrdup(s);
+ if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
+ abort();
+ if ((r = sshkey_read(pubkey, &cp)) != 0) {
+ error_fr(r, "parse");
+ abort();
+ }
+ free(tmp);
+ return pubkey;
+}
+
+static struct sshkey *
+privkey_or_die(const char *s)
+{
+ int r;
+ struct sshbuf *b;
+ struct sshkey *privkey;
+
+ if ((b = sshbuf_from(s, strlen(s))) == NULL) {
+ error_f("sshbuf_from failed");
+ abort();
+ }
+ if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
+ error_fr(r, "parse");
+ abort();
+ }
+ sshbuf_free(b);
+ return privkey;
+}
+
+static void
+add_key(const char *privkey, const char *certpath)
+{
+ Identity *id;
+ int r;
+ struct sshkey *cert;
+
+ id = xcalloc(1, sizeof(Identity));
+ TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
+ idtab->nentries++;
+ id->key = privkey_or_die(privkey);
+ id->comment = xstrdup("rhododaktulos Eos");
+ if (sshkey_is_sk(id->key))
+ id->sk_provider = xstrdup("internal");
+
+ /* Now the cert too */
+ id = xcalloc(1, sizeof(Identity));
+ TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
+ idtab->nentries++;
+ id->key = privkey_or_die(privkey);
+ cert = pubkey_or_die(certpath);
+ if ((r = sshkey_to_certified(id->key)) != 0) {
+ error_fr(r, "sshkey_to_certified");
+ abort();
+ }
+ if ((r = sshkey_cert_copy(cert, id->key)) != 0) {
+ error_fr(r, "sshkey_cert_copy");
+ abort();
+ }
+ sshkey_free(cert);
+ id->comment = xstrdup("outis");
+ if (sshkey_is_sk(id->key))
+ id->sk_provider = xstrdup("internal");
+}
+
+static void
+cleanup_idtab(void)
+{
+ Identity *id;
+
+ if (idtab == NULL) return;
+ for (id = TAILQ_FIRST(&idtab->idlist); id;
+ id = TAILQ_FIRST(&idtab->idlist)) {
+ TAILQ_REMOVE(&idtab->idlist, id, next);
+ free_identity(id);
+ }
+ free(idtab);
+ idtab = NULL;
+}
+
+static void
+reset_idtab(void)
+{
+ cleanup_idtab();
+ idtab_init();
+ // Load keys.
+ add_key(PRIV_RSA, CERT_RSA);
+ add_key(PRIV_DSA, CERT_DSA);
+ add_key(PRIV_ECDSA, CERT_ECDSA);
+ add_key(PRIV_ED25519, CERT_ED25519);
+ add_key(PRIV_ECDSA_SK, CERT_ECDSA_SK);
+ add_key(PRIV_ED25519_SK, CERT_ED25519_SK);
+}
+
+static void
+cleanup_sockettab(void)
+{
+ u_int i;
+ for (i = 0; i < sockets_alloc; i++) {
+ if (sockets[i].type != AUTH_UNUSED)
+ close_socket(sockets + i);
+ }
+ free(sockets);
+ sockets = NULL;
+ sockets_alloc = 0;
+}
+
+static void
+reset_sockettab(int devnull)
+{
+ int fd;
+
+ cleanup_sockettab();
+ if ((fd = dup(devnull)) == -1) {
+ error_f("dup: %s", strerror(errno));
+ abort();
+ }
+ new_socket(AUTH_CONNECTION, fd);
+ assert(sockets[0].type == AUTH_CONNECTION);
+ assert(sockets[0].fd == fd);
+}
+
+#define MAX_MESSAGES 256
+void
+test_one(const uint8_t* s, size_t slen)
+{
+ static int devnull = -1;
+ size_t i, olen, nlen;
+
+ if (devnull == -1) {
+ log_init(__progname, SYSLOG_LEVEL_DEBUG3,
+ SYSLOG_FACILITY_AUTH, 1);
+ devnull = devnull_or_die();
+ allowed_providers = xstrdup("");
+ setenv("DISPLAY", "", 1); /* ban askpass */
+ }
+
+ reset_idtab();
+ reset_sockettab(devnull);
+ (void)sshbuf_put(sockets[0].input, s, slen);
+ for (i = 0; i < MAX_MESSAGES; i++) {
+ olen = sshbuf_len(sockets[0].input);
+ process_message(0);
+ nlen = sshbuf_len(sockets[0].input);
+ if (nlen == 0 || nlen == olen)
+ break;
+ }
+ cleanup_idtab();
+ cleanup_sockettab();
+}
diff --git a/regress/misc/fuzz-harness/fixed-keys.h b/regress/misc/fuzz-harness/fixed-keys.h
new file mode 100644
index 000000000..c6e7c6cc1
--- /dev/null
+++ b/regress/misc/fuzz-harness/fixed-keys.h
@@ -0,0 +1,119 @@
+/*
+ * Some keys used by fuzzers
+ */
+
+#define PRIV_RSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"\
+"NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5\n"\
+"thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU\n"\
+"d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW\n"\
+"3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt\n"\
+"iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I\n"\
+"8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK\n"\
+"6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm\n"\
+"DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml\n"\
+"MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T\n"\
+"t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v\n"\
+"/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM\n"\
+"SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB\n"\
+"ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx\n"\
+"jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4\n"\
+"JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg\n"\
+"YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh\n"\
+"VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h\n"\
+"Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU\n"\
+"0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt\n"\
+"7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+\n"\
+"ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9\n"\
+"jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl\n"\
+"t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW\n"\
+"I79JhtGkh+GtcnkEfwAAAAAB\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_RSA \
+"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT"
+#define CERT_RSA \
+"ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub"
+#define PRIV_DSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\
+"NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\
+"xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\
+"3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\
+"d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\
+"44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\
+"THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\
+"kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\
+"ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\
+"h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\
+"R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\
+"mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\
+"VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\
+"4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\
+"oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\
+"WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\
+"ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\
+"z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\
+"lq8AAAAAAQI=\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_DSA \
+"ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8="
+#define CERT_DSA \
+"ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub"
+#define PRIV_ECDSA \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\
+"1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\
+"6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\
+"6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\
+"onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\
+"sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ECDSA \
+"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs="
+#define CERT_ECDSA \
+"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub"
+#define PRIV_ED25519 \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"\
+"QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/\n"\
+"fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw\n"\
+"AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP\n"\
+"Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ED25519 \
+"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD"
+#define CERT_ED25519 \
+"ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub"
+#define PRIV_ECDSA_SK \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2\n"\
+"RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1\n"\
+"VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB\n"\
+"X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv\n"\
+"cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm\n"\
+"wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt\n"\
+"LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn\n"\
+"dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn\n"\
+"QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW\n"\
+"hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ\n"\
+"UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ\n"\
+"IDBAUG\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ECDSA_SK \
+"sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg=="
+#define CERT_ECDSA_SK \
+"sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E"
+#define PRIV_ED25519_SK \
+"-----BEGIN OPENSSH PRIVATE KEY-----\n"\
+"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2\n"\
+"gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je\n"\
+"RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2\n"\
+"9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS\n"\
+"xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq\n"\
+"mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg==\n"\
+"-----END OPENSSH PRIVATE KEY-----\n"
+#define PUB_ED25519_SK \
+"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo="
+#define CERT_ED25519_SK \
+"sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA=="
diff --git a/regress/misc/fuzz-harness/kex_fuzz.cc b/regress/misc/fuzz-harness/kex_fuzz.cc
new file mode 100644
index 000000000..4740a7cb0
--- /dev/null
+++ b/regress/misc/fuzz-harness/kex_fuzz.cc
@@ -0,0 +1,461 @@
+// libfuzzer driver for key exchange fuzzing.
+
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+
+#include "includes.h"
+#include "ssherr.h"
+#include "ssh_api.h"
+#include "sshbuf.h"
+#include "packet.h"
+#include "myproposal.h"
+#include "xmalloc.h"
+#include "authfile.h"
+#include "log.h"
+
+#include "fixed-keys.h"
+
+// Define if you want to generate traces.
+/* #define STANDALONE 1 */
+
+static int prepare_key(struct shared_state *st, int keytype, int bits);
+
+struct shared_state {
+ size_t nkeys;
+ struct sshkey **privkeys, **pubkeys;
+};
+
+struct test_state {
+ struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */
+ struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */
+ struct sshbuf *s_template, *c_template; /* main copy of input */
+};
+
+static int
+do_send_and_receive(struct ssh *from, struct ssh *to,
+ struct sshbuf *store, int clobber, size_t *n)
+{
+ u_char type;
+ size_t len;
+ const u_char *buf;
+ int r;
+
+ for (*n = 0;; (*n)++) {
+ if ((r = ssh_packet_next(from, &type)) != 0) {
+ debug_fr(r, "ssh_packet_next");
+ return r;
+ }
+ if (type != 0)
+ return 0;
+ buf = ssh_output_ptr(from, &len);
+ debug_f("%zu%s", len, clobber ? " ignore" : "");
+ if (len == 0)
+ return 0;
+ if ((r = ssh_output_consume(from, len)) != 0) {
+ debug_fr(r, "ssh_output_consume");
+ return r;
+ }
+ if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) {
+ debug_fr(r, "sshbuf_put");
+ return r;
+ }
+ if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) {
+ debug_fr(r, "ssh_input_append");
+ return r;
+ }
+ }
+}
+
+static int
+run_kex(struct test_state *ts, struct ssh *client, struct ssh *server)
+{
+ int r = 0;
+ size_t cn, sn;
+
+ /* If fuzzing, replace server/client input */
+ if (ts->sin != NULL) {
+ if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin),
+ sshbuf_len(ts->sin))) != 0) {
+ error_fr(r, "ssh_input_append");
+ return r;
+ }
+ sshbuf_reset(ts->sin);
+ }
+ if (ts->cin != NULL) {
+ if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin),
+ sshbuf_len(ts->cin))) != 0) {
+ error_fr(r, "ssh_input_append");
+ return r;
+ }
+ sshbuf_reset(ts->cin);
+ }
+ while (!server->kex->done || !client->kex->done) {
+ cn = sn = 0;
+ debug_f("S:");
+ if ((r = do_send_and_receive(server, client,
+ ts->smsgs, ts->cin != NULL, &sn)) != 0) {
+ debug_fr(r, "S->C");
+ break;
+ }
+ debug_f("C:");
+ if ((r = do_send_and_receive(client, server,
+ ts->cmsgs, ts->sin != NULL, &cn)) != 0) {
+ debug_fr(r, "C->S");
+ break;
+ }
+ if (cn == 0 && sn == 0) {
+ debug_f("kex stalled");
+ r = SSH_ERR_PROTOCOL_ERROR;
+ break;
+ }
+ }
+ debug_fr(r, "done");
+ return r;
+}
+
+static void
+store_key(struct shared_state *st, struct sshkey *pubkey,
+ struct sshkey *privkey)
+{
+ if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX ||
+ privkey->type != pubkey->type ||
+ ((size_t)pubkey->type < st->nkeys &&
+ st->pubkeys[pubkey->type] != NULL))
+ abort();
+ if ((size_t)pubkey->type >= st->nkeys) {
+ st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys,
+ st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys));
+ st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys,
+ st->nkeys, privkey->type + 1, sizeof(*st->privkeys));
+ st->nkeys = privkey->type + 1;
+ }
+ debug_f("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type);
+ st->pubkeys[pubkey->type] = pubkey;
+ st->privkeys[privkey->type] = privkey;
+}
+
+static int
+prepare_keys(struct shared_state *st)
+{
+ if (prepare_key(st, KEY_RSA, 2048) != 0 ||
+ prepare_key(st, KEY_DSA, 1024) != 0 ||
+ prepare_key(st, KEY_ECDSA, 256) != 0 ||
+ prepare_key(st, KEY_ED25519, 256) != 0) {
+ error_f("key prepare failed");
+ return -1;
+ }
+ return 0;
+}
+
+static struct sshkey *
+get_pubkey(struct shared_state *st, int keytype)
+{
+ if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
+ st->pubkeys == NULL || st->pubkeys[keytype] == NULL)
+ abort();
+ return st->pubkeys[keytype];
+}
+
+static struct sshkey *
+get_privkey(struct shared_state *st, int keytype)
+{
+ if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
+ st->privkeys == NULL || st->privkeys[keytype] == NULL)
+ abort();
+ return st->privkeys[keytype];
+}
+
+static int
+do_kex_with_key(struct shared_state *st, struct test_state *ts,
+ const char *kex, int keytype)
+{
+ struct ssh *client = NULL, *server = NULL;
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ struct sshbuf *state = NULL;
+ struct kex_params kex_params;
+ const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT };
+ char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL;
+ int i, r;
+
+ ts->cin = ts->sin = NULL;
+ if (ts->c_template != NULL &&
+ (ts->cin = sshbuf_fromb(ts->c_template)) == NULL)
+ abort();
+ if (ts->s_template != NULL &&
+ (ts->sin = sshbuf_fromb(ts->s_template)) == NULL)
+ abort();
+
+ pubkey = get_pubkey(st, keytype);
+ privkey = get_privkey(st, keytype);
+ keyname = xstrdup(sshkey_ssh_name(privkey));
+ if (ts->cin != NULL) {
+ debug_f("%s %s clobber client %zu", kex, keyname,
+ sshbuf_len(ts->cin));
+ } else if (ts->sin != NULL) {
+ debug_f("%s %s clobber server %zu", kex, keyname,
+ sshbuf_len(ts->sin));
+ } else
+ debug_f("%s %s noclobber", kex, keyname);
+
+ for (i = 0; i < PROPOSAL_MAX; i++) {
+ ccp = proposal[i];
+#ifdef CIPHER_NONE_AVAIL
+ if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC)
+ ccp = "none";
+#endif
+ if (i == PROPOSAL_SERVER_HOST_KEY_ALGS)
+ ccp = keyname;
+ else if (i == PROPOSAL_KEX_ALGS && kex != NULL)
+ ccp = kex;
+ if ((myproposal[i] = strdup(ccp)) == NULL) {
+ error_f("strdup prop %d", i);
+ goto fail;
+ }
+ }
+ memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
+ if ((r = ssh_init(&client, 0, &kex_params)) != 0) {
+ error_fr(r, "init client");
+ goto fail;
+ }
+ if ((r = ssh_init(&server, 1, &kex_params)) != 0) {
+ error_fr(r, "init server");
+ goto fail;
+ }
+ if ((r = ssh_add_hostkey(server, privkey)) != 0 ||
+ (r = ssh_add_hostkey(client, pubkey)) != 0) {
+ error_fr(r, "add hostkeys");
+ goto fail;
+ }
+ if ((r = run_kex(ts, client, server)) != 0) {
+ error_fr(r, "kex");
+ goto fail;
+ }
+ /* XXX rekex, set_state, etc */
+ fail:
+ for (i = 0; i < PROPOSAL_MAX; i++)
+ free(myproposal[i]);
+ sshbuf_free(ts->sin);
+ sshbuf_free(ts->cin);
+ sshbuf_free(state);
+ ssh_free(client);
+ ssh_free(server);
+ free(keyname);
+ return r;
+}
+
+static int
+prepare_key(struct shared_state *st, int kt, int bits)
+{
+ const char *pubstr = NULL;
+ const char *privstr = NULL;
+ char *tmp, *cp;
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ struct sshbuf *b = NULL;
+ int r;
+
+ switch (kt) {
+ case KEY_RSA:
+ pubstr = PUB_RSA;
+ privstr = PRIV_RSA;
+ break;
+ case KEY_DSA:
+ pubstr = PUB_DSA;
+ privstr = PRIV_DSA;
+ break;
+ case KEY_ECDSA:
+ pubstr = PUB_ECDSA;
+ privstr = PRIV_ECDSA;
+ break;
+ case KEY_ED25519:
+ pubstr = PUB_ED25519;
+ privstr = PRIV_ED25519;
+ break;
+ default:
+ abort();
+ }
+ if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL)
+ abort();
+ if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
+ error_fr(r, "priv %d", kt);
+ abort();
+ }
+ sshbuf_free(b);
+ tmp = cp = xstrdup(pubstr);
+ if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
+ abort();
+ if ((r = sshkey_read(pubkey, &cp)) != 0) {
+ error_fr(r, "pub %d", kt);
+ abort();
+ }
+ free(tmp);
+
+ store_key(st, pubkey, privkey);
+ return 0;
+}
+
+#if defined(STANDALONE)
+
+#if 0 /* use this if generating new keys to embed above */
+static int
+prepare_key(struct shared_state *st, int keytype, int bits)
+{
+ struct sshkey *privkey = NULL, *pubkey = NULL;
+ int r;
+
+ if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) {
+ error_fr(r, "generate");
+ abort();
+ }
+ if ((r = sshkey_from_private(privkey, &pubkey)) != 0) {
+ error_fr(r, "make pubkey");
+ abort();
+ }
+ store_key(st, pubkey, privkey);
+ return 0;
+}
+#endif
+
+int main(void)
+{
+ static struct shared_state *st;
+ struct test_state *ts;
+ const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 };
+ const char *kextypes[] = {
+ "sntrup761x25519-sha512@openssh.com",
+ "curve25519-sha256@libssh.org",
+ "ecdh-sha2-nistp256",
+ "diffie-hellman-group1-sha1",
+ "diffie-hellman-group-exchange-sha1",
+ NULL,
+ };
+ int i, j;
+ char *path;
+ FILE *f;
+
+ log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
+
+ if (st == NULL) {
+ st = (struct shared_state *)xcalloc(1, sizeof(*st));
+ prepare_keys(st);
+ }
+ /* Run each kex method for each key and save client/server packets */
+ for (i = 0; keytypes[i] != -1; i++) {
+ for (j = 0; kextypes[j] != NULL; j++) {
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ ts->smsgs = sshbuf_new();
+ ts->cmsgs = sshbuf_new();
+ do_kex_with_key(st, ts, kextypes[j], keytypes[i]);
+ xasprintf(&path, "S2C-%s-%s",
+ kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if ((f = fopen(path, "wb+")) == NULL)
+ abort();
+ if (fwrite(sshbuf_ptr(ts->smsgs), 1,
+ sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs))
+ abort();
+ fclose(f);
+ free(path);
+ //sshbuf_dump(ts->smsgs, stderr);
+ xasprintf(&path, "C2S-%s-%s",
+ kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if ((f = fopen(path, "wb+")) == NULL)
+ abort();
+ if (fwrite(sshbuf_ptr(ts->cmsgs), 1,
+ sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs))
+ abort();
+ fclose(f);
+ free(path);
+ //sshbuf_dump(ts->cmsgs, stderr);
+ sshbuf_free(ts->smsgs);
+ sshbuf_free(ts->cmsgs);
+ free(ts);
+ }
+ }
+ for (i = 0; keytypes[i] != -1; i++) {
+ xasprintf(&path, "%s.priv",
+ sshkey_type(st->privkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if (sshkey_save_private(st->privkeys[keytypes[i]], path,
+ "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0)
+ abort();
+ free(path);
+ xasprintf(&path, "%s.pub",
+ sshkey_type(st->pubkeys[keytypes[i]]));
+ debug_f("%s", path);
+ if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0)
+ abort();
+ free(path);
+ }
+}
+#else /* !STANDALONE */
+static void
+do_kex(struct shared_state *st, struct test_state *ts, const char *kex)
+{
+ do_kex_with_key(st, ts, kex, KEY_RSA);
+ do_kex_with_key(st, ts, kex, KEY_DSA);
+ do_kex_with_key(st, ts, kex, KEY_ECDSA);
+ do_kex_with_key(st, ts, kex, KEY_ED25519);
+}
+
+static void
+kex_tests(struct shared_state *st, struct test_state *ts)
+{
+ do_kex(st, ts, "sntrup761x25519-sha512@openssh.com");
+ do_kex(st, ts, "curve25519-sha256@libssh.org");
+ do_kex(st, ts, "ecdh-sha2-nistp256");
+ do_kex(st, ts, "diffie-hellman-group1-sha1");
+ do_kex(st, ts, "diffie-hellman-group-exchange-sha1");
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ static struct shared_state *st;
+ struct test_state *ts;
+ u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4];
+ u_char zbuf[4096] = {0};
+ static LogLevel loglevel = SYSLOG_LEVEL_INFO;
+
+ if (st == NULL) {
+ if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL)
+ loglevel = SYSLOG_LEVEL_DEBUG3;
+ log_init("kex_fuzz",
+ loglevel, SYSLOG_FACILITY_AUTH, 1);
+ st = (struct shared_state *)xcalloc(1, sizeof(*st));
+ prepare_keys(st);
+ }
+
+ /* Ensure that we can complete (fail) banner exchange at least */
+ memset(crbuf, '\n', sizeof(crbuf));
+
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ if ((ts->s_template = sshbuf_new()) == NULL ||
+ sshbuf_put(ts->s_template, data, size) != 0 ||
+ sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 ||
+ sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0)
+ abort();
+ kex_tests(st, ts);
+ sshbuf_free(ts->s_template);
+ free(ts);
+
+ ts = (struct test_state *)xcalloc(1, sizeof(*ts));
+ if ((ts->c_template = sshbuf_new()) == NULL ||
+ sshbuf_put(ts->c_template, data, size) != 0 ||
+ sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 ||
+ sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0)
+ abort();
+ kex_tests(st, ts);
+ sshbuf_free(ts->c_template);
+ free(ts);
+
+ return 0;
+}
+#endif /* STANDALONE */
+} /* extern "C" */
diff --git a/regress/misc/fuzz-harness/testdata/README b/regress/misc/fuzz-harness/testdata/README
new file mode 100644
index 000000000..752053001
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/README
@@ -0,0 +1,4 @@
+This is preparatory data for fuzzing testing including scripts and test keys,
+corresponding to ../fixed-keys that are used in the fuzz tests and consequent
+fuzzing seed corpora. They should not be changed unless the affected seed
+corpora are also regenerated.
diff --git a/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh
new file mode 100755
index 000000000..1043b9ff4
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Exercise ssh-agent to generate fuzzing corpus
+
+# XXX assumes agent hacked up with sk-dummy.o and ssh-sk.o linked directly
+# and dumping of e->request for each message.
+
+set -xe
+SSH_AUTH_SOCK=$PWD/sock
+rm -f agent-[0-9]* $SSH_AUTH_SOCK
+export SSH_AUTH_SOCK
+../../../../ssh-agent -D -a $SSH_AUTH_SOCK &
+sleep 1
+AGENT_PID=$!
+trap "kill $AGENT_PID" EXIT
+
+PRIV="id_dsa id_ecdsa id_ecdsa_sk id_ed25519 id_ed25519_sk id_rsa"
+
+# add keys
+ssh-add $PRIV
+
+# sign
+ssh-add -T *.pub
+
+# list
+ssh-add -l
+
+# remove individually
+ssh-add -d $PRIV
+
+# re-add with constraints
+ssh-add -c -t 3h $PRIV
+
+# delete all
+ssh-add -D
+
+# attempt to add a PKCS#11 token
+ssh-add -s /fake || :
+
+# attempt to delete PKCS#11
+ssh-add -e /fake || :
+
+ssh-add -L
+
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa b/regress/misc/fuzz-harness/testdata/id_dsa
new file mode 100644
index 000000000..88bf5566c
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa
@@ -0,0 +1,21 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH
+NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm
+xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA
+3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q
+d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP
+44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW
+THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O
+kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ
+ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs
+h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT
+R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B
+mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r
+VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS
+4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb
+oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc
+WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL
+ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ
+z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE
+lq8AAAAAAQI=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub
new file mode 100644
index 000000000..3afb87fe6
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub
@@ -0,0 +1 @@
+ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_dsa.pub b/regress/misc/fuzz-harness/testdata/id_dsa.pub
new file mode 100644
index 000000000..6f91c4e07
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8=
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa b/regress/misc/fuzz-harness/testdata/id_ecdsa
new file mode 100644
index 000000000..c1a96c6f9
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
+1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ
+6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW
+6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N
+onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ
+sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub
new file mode 100644
index 000000000..9de599917
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa-cert.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgVJZuM/1AOe6n++qRWMyUuAThYqLvvQxj5CGflLODp60AAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQsAAAAAAAAD6QAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAtdJpcF6ZmQL+ueices4QZeL7AK8Xuo08jyLgiolhjKy2jj4LSUki4aX/ZeZeJuby1ovGrfaeFAgx3itPLR7IAQ== id_ecdsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub
new file mode 100644
index 000000000..30a7cc23b
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk
new file mode 100644
index 000000000..5a364ed39
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk
@@ -0,0 +1,14 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
+RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQTYyU76zop1
+VOb4DfKWYnR5b0TOC3zw8DzObAfHWB5o6xls+tOYiEleXvIEi00Da2iCK47habZTOhLyeB
+X2Avu5AAAABHNzaDoAAAGYqUAQSKlAEEgAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
+cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEE2MlO+s6KdVTm+A3ylmJ0eW9Ezgt88PA8zm
+wHx1geaOsZbPrTmIhJXl7yBItNA2togiuO4Wm2UzoS8ngV9gL7uQAAAARzc2g6AQAAAOMt
+LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSHFsZjNsWTkxZFhwUn
+dYZDBrS0lYWmNpeDRRcDBNSU15Ny9JMUxXSTFuWG9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
+QUUyTWxPK3M2S2RWVG0rQTN5bG1KMGVXOUV6Z3Q4OFBBOHptd0h4MWdlYU9zWmJQclRtSW
+hKClhsN3lCSXROQTJ0b2dpdU80V20yVXpvUzhuZ1Y5Z0w3dVE9PQotLS0tLUVORCBFQyBQ
+UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAbZGptQGRqbS5zeWQuY29ycC5nb29nbGUuY29tAQ
+IDBAUG
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub
new file mode 100644
index 000000000..14040fad7
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk-cert.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgKLHtIca++5VoDrUAXU/KqGJZ7jZEnuJSTvt7VrYY9foAAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOgAAAAAAAAPqAAAAAQAAAAd1bHlzc2VzAAAAFwAAAAd1bHlzc2VzAAAACG9keXNzZXVzAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEB1naZOQDLaDr+fwn6E9x8/8HeiaUubDzPexfNQMz+m/7RD0gd5uJhHYUfDb5+/sIx1I7bUEeRIDkBbmZ2foo0E djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub
new file mode 100644
index 000000000..1b5e829b7
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ecdsa_sk.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBNjJTvrOinVU5vgN8pZidHlvRM4LfPDwPM5sB8dYHmjrGWz605iISV5e8gSLTQNraIIrjuFptlM6EvJ4FfYC+7kAAAAEc3NoOg== djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519 b/regress/misc/fuzz-harness/testdata/id_ed25519
new file mode 100644
index 000000000..6a7fbac92
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAIhWlP99VpT/
+fQAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAw
+AAAEDE1rlcMC0s0X3TKVZAOVavZOywwkXw8tO5dLObxaCMEDPQXmEVMVLmeFRyafKMVWgP
+Dkv8/uRBTwmcEDatZzMDAAAAAAECAwQF
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub
new file mode 100644
index 000000000..6a95fed2a
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519-cert.pub
@@ -0,0 +1 @@
+ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIMDQjYH6XRzH3j3MW1DdjCoAfvrHfgjnVGF+sLK0pBfqAAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMDAAAAAAAAA+sAAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBj0og+s09/HpwdHZbzN0twooKPDWWrxGfnP1Joy6cDnY2BCSQ7zg9vbq11kLF8H/sKOTZWAQrUZ7LlChOu9Ogw= id_ed25519.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519.pub b/regress/misc/fuzz-harness/testdata/id_ed25519.pub
new file mode 100644
index 000000000..87b617447
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519.pub
@@ -0,0 +1,2 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDPQXmEVMVLmeFRyafKMVWgPDkv8/uRBTwmcEDatZzMD
+
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk b/regress/misc/fuzz-harness/testdata/id_ed25519_sk
new file mode 100644
index 000000000..9dcda6c46
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
+gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCTJtH10vWhIDxd62edvMLg9u2cwYKyqa7332je
+RArHjAAAAARzc2g6AAAAwN7vvE3e77xNAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
+9tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoBAAAAQEsS
+xLFiVzfpH2mt9xh8i/zmHV646Hud4QruNBAGNl8gkybR9dL1oSA8XetnnbzC4PbtnMGCsq
+mu999o3kQKx4wAAAAAAAAAG2RqbUBkam0uc3lkLmNvcnAuZ29vZ2xlLmNvbQECAwQFBg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub
new file mode 100644
index 000000000..9e41eec00
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk-cert.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJiT+C/VLMWholFZ4xhOyJr0nSLZSFRIM3I07wUNTRPaAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDoAAAAAAAAD7AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAX0Pu13B94pVR3qq8MJQGkOS1Cd7AAM1k6O2VSwyDPM/LfsWIQ4ywgxDmk3hjXWOY7BqljuMxo5VO4JymEIhQBA== djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub
new file mode 100644
index 000000000..38d198444
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_ed25519_sk.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJMm0fXS9aEgPF3rZ528wuD27ZzBgrKprvffaN5ECseMAAAABHNzaDo= djm@djm.syd.corp.google.com
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa b/regress/misc/fuzz-harness/testdata/id_rsa
new file mode 100644
index 000000000..574fecf47
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa
@@ -0,0 +1,27 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEA3+epf+VGKoGPaAZXrf6S0cyumQnddkGBnVFX0A5eh37RtLug0qY5
+thxsBUbGGVr9mTd2QXwLujBwYg5l1MP/Fmg+5312Zgx9pHmS+qKULbar0hlNgptNEb+aNU
+d3o9qg3aXqXm7+ZnjAV05ef/mxNRN2ZvuEkw7cRppTJcbBI+vF3lXuCXnX2klDI95Gl2AW
+3WHRtanqLHZXuBkjjRBDKc7MUq/GP1hmLiAd95dvU7fZjRlIEsP84zGEI1Fb0L/kmPHcOt
+iVfHft8CtmC9v6+94JrOiPBBNScV+dyrgAGPsdKdr/1vIpQmCNiI8s3PCiD8J7ZiBaYm0I
+8fq5G/qnUwAAA7ggw2dXIMNnVwAAAAdzc2gtcnNhAAABAQDf56l/5UYqgY9oBlet/pLRzK
+6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZm
+DH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGml
+MlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29T
+t9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v
+/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAwEAAQAAAQEArWm5B4tFasppjUHM
+SsAuajtCxtizI1Hc10EW59cZM4vvUzE2f6+qZvdgWj3UU/L7Et23w0QVuSCnCerox379ZB
+ddEOFFAAiQjwBx65hbd4RRUymxtIQfjq18++LcMJW1nbVQ7c69ThQbtALIggmbS+ZE/8Gx
+jkwmIrCH0Ww8TlpsPe+mNHuyNk7UEZoXLm22lNLqq5qkIL5JgT6M2iNJpMOJy9/CKi6kO4
+JPuVwjdG4C5pBPaMN3KJ1IvAlSlLGNaXnfXcn85gWfsCjsZmH3liey2NJamqp/w83BrKUg
+YZvMR2qeWZaKkFTahpzN5KRK1BFeB37O0P84Dzh1biDX8QAAAIEAiWXW8ePYFwLpa2mFIh
+VvRTdcrN70rVK5eWVaL3pyS4vGA56Jixq86dHveOnbSY+iNb1jQidtXc8SWUt2wtHqZ32h
+Lji9/hMSKqe9SEP3xvDRDmUJqsVw0ySyrFrzm4160QY6RKU3CIQCVFslMZ9fxmrfZ/hxoU
+0X3FVsxmC4+kwAAACBAPOc1YERpV6PjANBrGR+1o1RCdACbm5myc42QzSNIaOZmgrYs+Gt
+7+EcoqSdbJzHJNCNQfF+A+vjbIkFiuZqq/5wwr59qXx5OAlijLB/ywwKmTWq6lp//Zxny+
+ka3sIGNO14eQvmxNDnlLL+RIZleCTEKBXSW6CZhr+uHMZFKKMtAAAAgQDrSkm+LbILB7H9
+jxEBZLhv53aAn4u81kFKQOJ7PzzpBGSoD12i7oIJu5siSD5EKDNVEr+SvCf0ISU3BuMpzl
+t3YrPrHRheOFhn5e3j0e//zB8rBC0DGB4CtTDdeh7rOXUL4K0pz+8wEpNkV62SWxhC6NRW
+I79JhtGkh+GtcnkEfwAAAAAB
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub
new file mode 100644
index 000000000..01761a38f
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa-cert.pub
@@ -0,0 +1 @@
+ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub
diff --git a/regress/misc/fuzz-harness/testdata/id_rsa.pub b/regress/misc/fuzz-harness/testdata/id_rsa.pub
new file mode 100644
index 000000000..05015e12b
--- /dev/null
+++ b/regress/misc/fuzz-harness/testdata/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT
diff --git a/regress/misc/kexfuzz/Makefile b/regress/misc/kexfuzz/Makefile
deleted file mode 100644
index ede5e2fb4..000000000
--- a/regress/misc/kexfuzz/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-# $OpenBSD: Makefile,v 1.8 2020/04/03 04:07:48 djm Exp $
-
-.include <bsd.own.mk>
-.include <bsd.obj.mk>
-
-# XXX detect from ssh binary?
-SSH1?= no
-OPENSSL?= yes
-
-PROG= kexfuzz
-SRCS= kexfuzz.c
-
-SSHREL=../../../../../usr.bin/ssh
-.PATH: ${.CURDIR}/${SSHREL}
-# From usr.bin/ssh
-SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
-SRCS+=atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c ssh-dss.c
-SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
-SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
-SRCS+=compat.c ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
-SRCS+=cipher-chachapoly.c chacha.c poly1305.c utf8.c
-SRCS+=sshbuf-io.c ssh-ecdsa-sk.c ssh-ed25519-sk.c msg.c ssh-sk-client.c
-
-SRCS+= kex.c
-SRCS+= dh.c
-SRCS+= kexdh.c
-SRCS+= kexecdh.c
-SRCS+= kexgex.c
-SRCS+= kexgexc.c
-SRCS+= kexgexs.c
-SRCS+= kexc25519.c
-SRCS+= smult_curve25519_ref.c
-SRCS+= kexgen.c
-SRCS+= kexsntrup4591761x25519.c
-SRCS+= sntrup4591761.c
-
-SRCS+=digest-openssl.c
-#SRCS+=digest-libc.c
-
-NOMAN= 1
-
-.if (${OPENSSL:L} == "yes")
-CFLAGS+= -DWITH_OPENSSL
-.else
-# SSH v.1 requires OpenSSL.
-SSH1= no
-.endif
-
-.if (${SSH1:L} == "yes")
-CFLAGS+= -DWITH_SSH1
-.endif
-
-LDADD+= -lfido2 -lcbor -lusbhid
-DPADD+= ${LIBFIDO2} ${LIBCBOR} ${LIBUSBHID}
-
-# enable warnings
-WARNINGS=Yes
-
-DEBUG=-g
-CFLAGS+= -fstack-protector-all
-CDIAGFLAGS= -Wall
-CDIAGFLAGS+= -Wextra
-CDIAGFLAGS+= -Werror
-CDIAGFLAGS+= -Wchar-subscripts
-CDIAGFLAGS+= -Wcomment
-CDIAGFLAGS+= -Wformat
-CDIAGFLAGS+= -Wformat-security
-CDIAGFLAGS+= -Wimplicit
-CDIAGFLAGS+= -Winline
-CDIAGFLAGS+= -Wmissing-declarations
-CDIAGFLAGS+= -Wmissing-prototypes
-CDIAGFLAGS+= -Wparentheses
-CDIAGFLAGS+= -Wpointer-arith
-CDIAGFLAGS+= -Wreturn-type
-CDIAGFLAGS+= -Wshadow
-CDIAGFLAGS+= -Wsign-compare
-CDIAGFLAGS+= -Wstrict-aliasing
-CDIAGFLAGS+= -Wstrict-prototypes
-CDIAGFLAGS+= -Wswitch
-CDIAGFLAGS+= -Wtrigraphs
-CDIAGFLAGS+= -Wuninitialized
-CDIAGFLAGS+= -Wunused
-CDIAGFLAGS+= -Wno-unused-parameter
-.if ${COMPILER_VERSION:L} != "gcc3"
-CDIAGFLAGS+= -Wold-style-definition
-.endif
-
-
-CFLAGS+=-I${.CURDIR}/${SSHREL}
-
-LDADD+= -lutil -lz
-DPADD+= ${LIBUTIL} ${LIBZ}
-
-.if (${OPENSSL:L} == "yes")
-LDADD+= -lcrypto
-DPADD+= ${LIBCRYPTO}
-.endif
-
-.include <bsd.prog.mk>
-
diff --git a/regress/misc/kexfuzz/README b/regress/misc/kexfuzz/README
deleted file mode 100644
index 504c26f3b..000000000
--- a/regress/misc/kexfuzz/README
+++ /dev/null
@@ -1,34 +0,0 @@
-This is a harness to help with fuzzing KEX.
-
-To use it, you first set it to count packets in each direction:
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key -c
-S2C: 29
-C2S: 31
-
-Then get it to record a particular packet (in this case the 4th
-packet from client->server):
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key \
- -d -D C2S -i 3 -f packet_3
-
-Fuzz the packet somehow:
-
-dd if=/dev/urandom of=packet_3 bs=32 count=1 # Just for example
-
-Then re-run the key exchange substituting the modified packet in
-its original sequence:
-
-./kexfuzz -K diffie-hellman-group1-sha1 -k host_ed25519_key \
- -r -D C2S -i 3 -f packet_3
-
-A comprehensive KEX fuzz run would fuzz every packet in both
-directions for each key exchange type and every hostkey type.
-This will take some time.
-
-Limitations: kexfuzz can't change the ordering of packets at
-present. It is limited to replacing individual packets with
-fuzzed variants with the same type. It really should allow
-insertion, deletion on replacement of packets too.
-
-$OpenBSD: README,v 1.3 2017/10/20 02:13:41 djm Exp $
diff --git a/regress/misc/kexfuzz/kexfuzz.c b/regress/misc/kexfuzz/kexfuzz.c
deleted file mode 100644
index 56697c918..000000000
--- a/regress/misc/kexfuzz/kexfuzz.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* $OpenBSD: kexfuzz.c,v 1.6 2020/01/26 00:09:50 djm Exp $ */
-/*
- * Fuzz harness for KEX code
- *
- * Placed in the public domain
- */
-
-#include "includes.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <stdio.h>
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#ifdef HAVE_ERR_H
-# include <err.h>
-#endif
-
-#include "ssherr.h"
-#include "ssh_api.h"
-#include "sshbuf.h"
-#include "packet.h"
-#include "myproposal.h"
-#include "authfile.h"
-#include "log.h"
-
-void kex_tests(void);
-static int do_debug = 0;
-
-enum direction { S2C, C2S };
-
-struct hook_ctx {
- struct ssh *client, *server, *server2;
- int *c2s, *s2c;
- int trigger_direction, packet_index;
- const char *dump_path;
- struct sshbuf *replace_data;
-};
-
-static int
-packet_hook(struct ssh *ssh, struct sshbuf *packet, u_char *typep, void *_ctx)
-{
- struct hook_ctx *ctx = (struct hook_ctx *)_ctx;
- int mydirection = ssh == ctx->client ? S2C : C2S;
- int *packet_count = mydirection == S2C ? ctx->s2c : ctx->c2s;
- FILE *dumpfile;
- int r;
-
- if (do_debug) {
- printf("%s packet %d type %u:\n",
- mydirection == S2C ? "s2c" : "c2s",
- *packet_count, *typep);
- sshbuf_dump(packet, stdout);
- }
- if (mydirection == ctx->trigger_direction &&
- ctx->packet_index == *packet_count) {
- if (ctx->replace_data != NULL) {
- sshbuf_reset(packet);
- /* Type is first byte of packet */
- if ((r = sshbuf_get_u8(ctx->replace_data,
- typep)) != 0 ||
- (r = sshbuf_putb(packet, ctx->replace_data)) != 0)
- return r;
- if (do_debug) {
- printf("***** replaced packet type %u\n",
- *typep);
- sshbuf_dump(packet, stdout);
- }
- } else if (ctx->dump_path != NULL) {
- if ((dumpfile = fopen(ctx->dump_path, "w+")) == NULL)
- err(1, "fopen %s", ctx->dump_path);
- /* Write { type, packet } */
- if (fwrite(typep, 1, 1, dumpfile) != 1)
- err(1, "fwrite type %s", ctx->dump_path);
- if (sshbuf_len(packet) != 0 &&
- fwrite(sshbuf_ptr(packet), sshbuf_len(packet),
- 1, dumpfile) != 1)
- err(1, "fwrite body %s", ctx->dump_path);
- if (do_debug) {
- printf("***** dumped packet type %u len %zu\n",
- *typep, sshbuf_len(packet));
- }
- fclose(dumpfile);
- /* No point in continuing */
- exit(0);
- }
- }
- (*packet_count)++;
- return 0;
-}
-
-static int
-do_send_and_receive(struct ssh *from, struct ssh *to)
-{
- u_char type;
- size_t len;
- const u_char *buf;
- int r;
-
- for (;;) {
- if ((r = ssh_packet_next(from, &type)) != 0) {
- fprintf(stderr, "ssh_packet_next: %s\n", ssh_err(r));
- return r;
- }
-
- if (type != 0)
- return 0;
- buf = ssh_output_ptr(from, &len);
- if (len == 0)
- return 0;
- if ((r = ssh_input_append(to, buf, len)) != 0) {
- debug("ssh_input_append: %s", ssh_err(r));
- return r;
- }
- if ((r = ssh_output_consume(from, len)) != 0) {
- debug("ssh_output_consume: %s", ssh_err(r));
- return r;
- }
- }
-}
-
-/* Minimal test_helper.c scaffholding to make this standalone */
-const char *in_test = NULL;
-#define TEST_START(a) \
- do { \
- in_test = (a); \
- if (do_debug) \
- fprintf(stderr, "test %s starting\n", in_test); \
- } while (0)
-#define TEST_DONE() \
- do { \
- if (do_debug) \
- fprintf(stderr, "test %s done\n", \
- in_test ? in_test : "???"); \
- in_test = NULL; \
- } while(0)
-#define ASSERT_INT_EQ(a, b) \
- do { \
- if ((int)(a) != (int)(b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%d) != expected %s (%d)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (int)(a), #b, (int)(b)); \
- exit(2); \
- } \
- } while (0)
-#define ASSERT_INT_GE(a, b) \
- do { \
- if ((int)(a) < (int)(b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%d) < expected %s (%d)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (int)(a), #b, (int)(b)); \
- exit(2); \
- } \
- } while (0)
-#define ASSERT_PTR_NE(a, b) \
- do { \
- if ((a) == (b)) { \
- fprintf(stderr, "%s %s:%d " \
- "%s (%p) != expected %s (%p)\n", \
- in_test ? in_test : "(none)", \
- __func__, __LINE__, #a, (a), #b, (b)); \
- exit(2); \
- } \
- } while (0)
-
-
-static void
-run_kex(struct ssh *client, struct ssh *server)
-{
- int r = 0;
-
- while (!server->kex->done || !client->kex->done) {
- if ((r = do_send_and_receive(server, client)) != 0) {
- debug("do_send_and_receive S2C: %s", ssh_err(r));
- break;
- }
- if ((r = do_send_and_receive(client, server)) != 0) {
- debug("do_send_and_receive C2S: %s", ssh_err(r));
- break;
- }
- }
- if (do_debug)
- printf("done: %s\n", ssh_err(r));
- ASSERT_INT_EQ(r, 0);
- ASSERT_INT_EQ(server->kex->done, 1);
- ASSERT_INT_EQ(client->kex->done, 1);
-}
-
-static void
-do_kex_with_key(const char *kex, struct sshkey *prvkey, int *c2s, int *s2c,
- int direction, int packet_index,
- const char *dump_path, struct sshbuf *replace_data)
-{
- struct ssh *client = NULL, *server = NULL, *server2 = NULL;
- struct sshkey *pubkey = NULL;
- struct sshbuf *state;
- struct kex_params kex_params;
- char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
- char *keyname = NULL;
- struct hook_ctx hook_ctx;
-
- TEST_START("sshkey_from_private");
- ASSERT_INT_EQ(sshkey_from_private(prvkey, &pubkey), 0);
- TEST_DONE();
-
- TEST_START("ssh_init");
- memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
- if (kex != NULL)
- kex_params.proposal[PROPOSAL_KEX_ALGS] = strdup(kex);
- keyname = strdup(sshkey_ssh_name(prvkey));
- ASSERT_PTR_NE(keyname, NULL);
- kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
- ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0);
- ASSERT_INT_EQ(ssh_init(&server, 1, &kex_params), 0);
- ASSERT_INT_EQ(ssh_init(&server2, 1, NULL), 0);
- ASSERT_PTR_NE(client, NULL);
- ASSERT_PTR_NE(server, NULL);
- ASSERT_PTR_NE(server2, NULL);
- TEST_DONE();
-
- hook_ctx.c2s = c2s;
- hook_ctx.s2c = s2c;
- hook_ctx.trigger_direction = direction;
- hook_ctx.packet_index = packet_index;
- hook_ctx.dump_path = dump_path;
- hook_ctx.replace_data = replace_data;
- hook_ctx.client = client;
- hook_ctx.server = server;
- hook_ctx.server2 = server2;
- ssh_packet_set_input_hook(client, packet_hook, &hook_ctx);
- ssh_packet_set_input_hook(server, packet_hook, &hook_ctx);
- ssh_packet_set_input_hook(server2, packet_hook, &hook_ctx);
-
- TEST_START("ssh_add_hostkey");
- ASSERT_INT_EQ(ssh_add_hostkey(server, prvkey), 0);
- ASSERT_INT_EQ(ssh_add_hostkey(client, pubkey), 0);
- TEST_DONE();
-
- TEST_START("kex");
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("rekeying client");
- ASSERT_INT_EQ(kex_send_kexinit(client), 0);
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("rekeying server");
- ASSERT_INT_EQ(kex_send_kexinit(server), 0);
- run_kex(client, server);
- TEST_DONE();
-
- TEST_START("ssh_packet_get_state");
- state = sshbuf_new();
- ASSERT_PTR_NE(state, NULL);
- ASSERT_INT_EQ(ssh_packet_get_state(server, state), 0);
- ASSERT_INT_GE(sshbuf_len(state), 1);
- TEST_DONE();
-
- TEST_START("ssh_packet_set_state");
- ASSERT_INT_EQ(ssh_add_hostkey(server2, prvkey), 0);
- kex_free(server2->kex); /* XXX or should ssh_packet_set_state()? */
- ASSERT_INT_EQ(ssh_packet_set_state(server2, state), 0);
- ASSERT_INT_EQ(sshbuf_len(state), 0);
- sshbuf_free(state);
- ASSERT_PTR_NE(server2->kex, NULL);
- /* XXX we need to set the callbacks */
-#ifdef WITH_OPENSSL
- server2->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
- server2->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
- server2->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
- server2->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
-# ifdef OPENSSL_HAS_ECC
- server2->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
-# endif
-#endif
- server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
- server2->kex->load_host_public_key = server->kex->load_host_public_key;
- server2->kex->load_host_private_key = server->kex->load_host_private_key;
- server2->kex->sign = server->kex->sign;
- TEST_DONE();
-
- TEST_START("rekeying server2");
- ASSERT_INT_EQ(kex_send_kexinit(server2), 0);
- run_kex(client, server2);
- ASSERT_INT_EQ(kex_send_kexinit(client), 0);
- run_kex(client, server2);
- TEST_DONE();
-
- TEST_START("cleanup");
- sshkey_free(pubkey);
- ssh_free(client);
- ssh_free(server);
- ssh_free(server2);
- free(keyname);
- TEST_DONE();
-}
-
-static void
-usage(void)
-{
- fprintf(stderr,
- "Usage: kexfuzz [-hcdrv] [-D direction] [-f data_file]\n"
- " [-K kex_alg] [-k private_key] [-i packet_index]\n"
- "\n"
- "Options:\n"
- " -h Display this help\n"
- " -c Count packets sent during KEX\n"
- " -d Dump mode: record KEX packet to data file\n"
- " -r Replace mode: replace packet with data file\n"
- " -v Turn on verbose logging\n"
- " -D S2C|C2S Packet direction for replacement or dump\n"
- " -f data_file Path to data file for replacement or dump\n"
- " -K kex_alg Name of KEX algorithm to test (see below)\n"
- " -k private_key Path to private key file\n"
- " -i packet_index Index of packet to replace or dump (from 0)\n"
- "\n"
- "Available KEX algorithms: %s\n", kex_alg_list(' '));
-}
-
-static void
-badusage(const char *bad)
-{
- fprintf(stderr, "Invalid options\n");
- fprintf(stderr, "%s\n", bad);
- usage();
- exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
- int ch, fd, r;
- int count_flag = 0, dump_flag = 0, replace_flag = 0;
- int packet_index = -1, direction = -1;
- int s2c = 0, c2s = 0; /* packet counts */
- const char *kex = NULL, *kpath = NULL, *data_path = NULL;
- struct sshkey *key = NULL;
- struct sshbuf *replace_data = NULL;
-
- setvbuf(stdout, NULL, _IONBF, 0);
- while ((ch = getopt(argc, argv, "hcdrvD:f:K:k:i:")) != -1) {
- switch (ch) {
- case 'h':
- usage();
- return 0;
- case 'c':
- count_flag = 1;
- break;
- case 'd':
- dump_flag = 1;
- break;
- case 'r':
- replace_flag = 1;
- break;
- case 'v':
- do_debug = 1;
- break;
-
- case 'D':
- if (strcasecmp(optarg, "s2c") == 0)
- direction = S2C;
- else if (strcasecmp(optarg, "c2s") == 0)
- direction = C2S;
- else
- badusage("Invalid direction (-D)");
- break;
- case 'f':
- data_path = optarg;
- break;
- case 'K':
- kex = optarg;
- break;
- case 'k':
- kpath = optarg;
- break;
- case 'i':
- packet_index = atoi(optarg);
- if (packet_index < 0)
- badusage("Invalid packet index");
- break;
- default:
- badusage("unsupported flag");
- }
- }
- argc -= optind;
- argv += optind;
-
- log_init(argv[0], do_debug ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
- SYSLOG_FACILITY_USER, 1);
-
- /* Must select a single mode */
- if ((count_flag + dump_flag + replace_flag) != 1)
- badusage("Must select one mode: -c, -d or -r");
- /* KEX type is mandatory */
- if (kex == NULL || !kex_names_valid(kex) || strchr(kex, ',') != NULL)
- badusage("Missing or invalid kex type (-K flag)");
- /* Valid key is mandatory */
- if (kpath == NULL)
- badusage("Missing private key (-k flag)");
- if ((fd = open(kpath, O_RDONLY)) == -1)
- err(1, "open %s", kpath);
- if ((r = sshkey_load_private_type_fd(fd, KEY_UNSPEC, NULL,
- &key, NULL)) != 0)
- errx(1, "Unable to load key %s: %s", kpath, ssh_err(r));
- close(fd);
- /* XXX check that it is a private key */
- /* XXX support certificates */
- if (key == NULL || key->type == KEY_UNSPEC)
- badusage("Invalid key file (-k flag)");
-
- /* Replace (fuzz) mode */
- if (replace_flag) {
- if (packet_index == -1 || direction == -1 || data_path == NULL)
- badusage("Replace (-r) mode must specify direction "
- "(-D) packet index (-i) and data path (-f)");
- if ((r = sshbuf_load_file(data_path, &replace_data)) != 0)
- errx(1, "read %s: %s", data_path, ssh_err(r));
- }
-
- /* Dump mode */
- if (dump_flag) {
- if (packet_index == -1 || direction == -1 || data_path == NULL)
- badusage("Dump (-d) mode must specify direction "
- "(-D), packet index (-i) and data path (-f)");
- }
-
- /* Count mode needs no further flags */
-
- do_kex_with_key(kex, key, &c2s, &s2c,
- direction, packet_index,
- dump_flag ? data_path : NULL,
- replace_flag ? replace_data : NULL);
- sshkey_free(key);
- sshbuf_free(replace_data);
-
- if (count_flag) {
- printf("S2C: %d\n", s2c);
- printf("C2S: %d\n", c2s);
- }
-
- return 0;
-}
diff --git a/regress/misc/sk-dummy/fatal.c b/regress/misc/sk-dummy/fatal.c
index 7cdc74b97..c6e4b5d6f 100644
--- a/regress/misc/sk-dummy/fatal.c
+++ b/regress/misc/sk-dummy/fatal.c
@@ -1,20 +1,27 @@
/* public domain */
+#include "includes.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
-void fatal(char *fmt, ...);
+#include "log.h"
void
-fatal(char *fmt, ...)
+sshfatal(const char *file, const char *func, int line, int showfunc,
+ LogLevel level, const char *suffix, const char *fmt, ...)
{
va_list ap;
+ if (showfunc)
+ fprintf(stderr, "%s: ", func);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
+ if (suffix != NULL)
+ fprintf(stderr, ": %s", suffix);
fputc('\n', stderr);
_exit(1);
}
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
index f3acb2fb7..4003362d7 100644
--- a/regress/misc/sk-dummy/sk-dummy.c
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -47,10 +47,17 @@
} while (0)
#endif
-#if SSH_SK_VERSION_MAJOR != 0x00050000
+#if SSH_SK_VERSION_MAJOR != 0x00070000
# error SK API has changed, sk-dummy.c needs an update
#endif
+#ifdef SK_DUMMY_INTEGRATE
+# define sk_api_version ssh_sk_api_version
+# define sk_enroll ssh_sk_enroll
+# define sk_sign ssh_sk_sign
+# define sk_load_resident_keys ssh_sk_load_resident_keys
+#endif /* !SK_STANDALONE */
+
static void skdebug(const char *func, const char *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
diff --git a/regress/multiplex.sh b/regress/multiplex.sh
index 817ddbfa8..4744fa3d9 100644
--- a/regress/multiplex.sh
+++ b/regress/multiplex.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: multiplex.sh,v 1.32 2020/01/25 02:57:53 dtucker Exp $
+# $OpenBSD: multiplex.sh,v 1.33 2020/06/24 15:16:23 markus Exp $
# Placed in the Public Domain.
make_tmpdir
@@ -97,22 +97,24 @@ kill $netcat_pid 2>/dev/null
rm -f ${COPY} $OBJ/unix-[123].fwd
for s in 0 1 4 5 44; do
- trace "exit status $s over multiplexed connection"
- verbose "test $tid: status $s"
- ${SSH} -F $OBJ/ssh_config -S $CTL otherhost exit $s
+ for mode in "" "-Oproxy"; do
+ trace "exit status $s over multiplexed connection ($mode)"
+ verbose "test $tid: status $s ($mode)"
+ ${SSH} -F $OBJ/ssh_config -S $CTL $mode otherhost exit $s
r=$?
if [ $r -ne $s ]; then
fail "exit code mismatch: $r != $s"
fi
# same with early close of stdout/err
- trace "exit status $s with early close over multiplexed connection"
- ${SSH} -F $OBJ/ssh_config -S $CTL -n otherhost \
+ trace "exit status $s with early close over multiplexed connection ($mode)"
+ ${SSH} -F $OBJ/ssh_config -S $CTL -n $mode otherhost \
exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\'
r=$?
if [ $r -ne $s ]; then
fail "exit code (with sleep) mismatch: $r != $s"
fi
+ done
done
verbose "test $tid: cmd check"
diff --git a/regress/multipubkey.sh b/regress/multipubkey.sh
index 9b2273353..8cdda1a9a 100644
--- a/regress/multipubkey.sh
+++ b/regress/multipubkey.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: multipubkey.sh,v 1.3 2019/12/11 18:47:14 djm Exp $
+# $OpenBSD: multipubkey.sh,v 1.4 2021/06/07 01:16:34 djm Exp $
# Placed in the Public Domain.
tid="multiple pubkey"
@@ -31,27 +31,35 @@ grep -v IdentityFile $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy
opts="-oProtocol=2 -F $OBJ/ssh_proxy -oIdentitiesOnly=yes"
opts="$opts -i $OBJ/cert_user_key1 -i $OBJ/user_key1 -i $OBJ/user_key2"
-for privsep in yes ; do
+for match in no yes ; do
(
- grep -v "Protocol" $OBJ/sshd_proxy.orig
+ cat $OBJ/sshd_proxy.orig
echo "Protocol 2"
- echo "UsePrivilegeSeparation $privsep"
- echo "AuthenticationMethods publickey,publickey"
echo "TrustedUserCAKeys $OBJ/user_ca_key.pub"
echo "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u"
) > $OBJ/sshd_proxy
+ if test "$match" = "yes" ; then
+ echo "AuthenticationMethods none" >> $OBJ/sshd_proxy
+ echo "PubkeyAuthentication no" >> $OBJ/sshd_proxy
+ echo "Match all" >> $OBJ/sshd_proxy
+ echo "PubkeyAuthentication yes" >> $OBJ/sshd_proxy
+ fi
+ echo "AuthenticationMethods publickey,publickey" >> $OBJ/sshd_proxy
# Single key should fail.
+ trace "match $match single key"
rm -f $OBJ/authorized_principals_$USER
cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER
${SSH} $opts proxy true && fail "ssh succeeded with key"
# Single key with same-public cert should fail.
+ trace "match $match pubkey + identical cert"
echo mekmitasdigoat > $OBJ/authorized_principals_$USER
cat $OBJ/user_key1.pub > $OBJ/authorized_keys_$USER
${SSH} $opts proxy true && fail "ssh succeeded with key+cert"
# Multiple plain keys should succeed.
+ trace "match $match multiple public"
rm -f $OBJ/authorized_principals_$USER
cat $OBJ/user_key1.pub $OBJ/user_key2.pub > \
$OBJ/authorized_keys_$USER
@@ -59,6 +67,7 @@ for privsep in yes ; do
# Cert and different key should succeed
# Key and different-public cert should succeed.
+ trace "match $match pubkey + different cert"
echo mekmitasdigoat > $OBJ/authorized_principals_$USER
cat $OBJ/user_key2.pub > $OBJ/authorized_keys_$USER
${SSH} $opts proxy true || fail "ssh failed with key/cert"
diff --git a/regress/netcat.c b/regress/netcat.c
index fe94dd908..20ec3f595 100644
--- a/regress/netcat.c
+++ b/regress/netcat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu Exp $ */
+/* $OpenBSD: netcat.c,v 1.131 2015/09/03 23:06:28 sobrado Exp $ */
/*
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
*
@@ -44,14 +44,15 @@
#include <netinet/ip.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
#include <netdb.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
#include "atomicio.h"
#ifdef HAVE_POLL_H
@@ -68,6 +69,9 @@
# include <sys/byteorder.h>
#endif
+/* rename to avoid collision in libssh */
+#define timeout_connect netcat_timeout_connect
+
/* Telnet options from arpa/telnet.h */
#define IAC 255
#define DONT 254
@@ -133,7 +137,7 @@ int udptest(int);
int unix_bind(char *);
int unix_connect(char *);
int unix_listen(char *);
-void set_common_sockopts(int);
+void set_common_sockopts(int, int);
int map_tos(char *, int *);
void report_connect(const struct sockaddr *, socklen_t);
void usage(int);
@@ -162,6 +166,8 @@ main(int argc, char *argv[])
uport = NULL;
sv = NULL;
+ signal(SIGPIPE, SIG_IGN);
+
while ((ch = getopt(argc, argv,
"46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
switch (ch) {
@@ -648,7 +654,7 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
freeaddrinfo(ares);
}
- set_common_sockopts(s);
+ set_common_sockopts(s, res0->ai_family);
if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
break;
@@ -748,7 +754,7 @@ local_listen(char *host, char *port, struct addrinfo hints)
if (ret == -1)
err(1, "setsockopt SO_REUSEADDR");
#endif
- set_common_sockopts(s);
+ set_common_sockopts(s, res0->ai_family);
if (bind(s, (struct sockaddr *)res0->ai_addr,
res0->ai_addrlen) == 0)
@@ -1034,17 +1040,17 @@ fdpass(int nfd)
bzero(&pfd, sizeof(pfd));
pfd.fd = STDOUT_FILENO;
+ pfd.events = POLLOUT;
for (;;) {
r = sendmsg(STDOUT_FILENO, &msg, 0);
if (r == -1) {
if (errno == EAGAIN || errno == EINTR) {
- pfd.events = POLLOUT;
if (poll(&pfd, 1, -1) == -1)
err(1, "poll");
continue;
}
err(1, "sendmsg");
- } else if (r == -1)
+ } else if (r != 1)
errx(1, "sendmsg: unexpected return value %zd", r);
else
break;
@@ -1168,7 +1174,7 @@ udptest(int s)
}
void
-set_common_sockopts(int s)
+set_common_sockopts(int s, int af)
{
int x = 1;
@@ -1184,10 +1190,19 @@ set_common_sockopts(int s)
&x, sizeof(x)) == -1)
err(1, "setsockopt");
}
-#ifdef IP_TOS
+#if defined(IP_TOS) && defined(IPV6_TCLASS)
if (Tflag != -1) {
- if (setsockopt(s, IPPROTO_IP, IP_TOS,
- &Tflag, sizeof(Tflag)) == -1)
+ int proto, option;
+
+ if (af == AF_INET6) {
+ proto = IPPROTO_IPV6;
+ option = IPV6_TCLASS;
+ } else {
+ proto = IPPROTO_IP;
+ option = IP_TOS;
+ }
+
+ if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1)
err(1, "set IP ToS");
}
#endif
@@ -1321,7 +1336,7 @@ usage(int ret)
{
fprintf(stderr,
"usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
- "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n"
+ "\t [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n"
"\t [-V rtable] [-w timeout] [-X proxy_protocol]\n"
"\t [-x proxy_address[:port]] [destination] [port]\n");
if (ret)
diff --git a/regress/percent.sh b/regress/percent.sh
index 2e891f693..7ed41845b 100644
--- a/regress/percent.sh
+++ b/regress/percent.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: percent.sh,v 1.6 2020/04/10 00:54:03 dtucker Exp $
+# $OpenBSD: percent.sh,v 1.13 2021/07/25 12:13:03 dtucker Exp $
# Placed in the Public Domain.
tid="percent expansions"
@@ -25,12 +25,21 @@ trial()
trace "test $opt=$arg $expect"
rm -f $OBJ/actual
+ got=""
case "$opt" in
localcommand)
${SSH} -F $OBJ/ssh_proxy -o $opt="echo '$arg' >$OBJ/actual" \
somehost true
got=`cat $OBJ/actual`
;;
+ userknownhostsfile)
+ # Move the userknownhosts file to what the expansion says,
+ # make sure ssh works then put it back.
+ mv "$OBJ/known_hosts" "$OBJ/$expect"
+ ${SSH} -F $OBJ/ssh_proxy -o $opt="$OBJ/$arg" somehost true && \
+ got="$expect"
+ mv "$OBJ/$expect" "$OBJ/known_hosts"
+ ;;
matchexec)
(cat $OBJ/ssh_proxy && \
echo "Match Exec \"echo '$arg' >$OBJ/actual\"") \
@@ -55,34 +64,56 @@ trial()
}
for i in matchexec localcommand remotecommand controlpath identityagent \
- forwardagent localforward remoteforward; do
- verbose $tid $i
- if [ "$i" = "localcommand" ]; then
- REMUSER=$USER
+ forwardagent localforward remoteforward userknownhostsfile; do
+ verbose $tid $i percent
+ case "$i" in
+ localcommand|userknownhostsfile)
+ # Any test that's going to actually make a connection needs
+ # to use the real username.
+ REMUSER=$USER ;;
+ *)
+ REMUSER=remuser ;;
+ esac
+ if [ "$i" = "$localcommand" ]; then
trial $i '%T' NONE
- else
- REMUSER=remuser
fi
# Matches implementation in readconf.c:ssh_connection_hash()
HASH=`printf "${HOSTNAME}127.0.0.1${PORT}$REMUSER" |
- openssl sha1 | cut -f2 -d' '`
+ $OPENSSL_BIN sha1 | cut -f2 -d' '`
trial $i '%%' '%'
trial $i '%C' $HASH
trial $i '%i' $USERID
trial $i '%h' 127.0.0.1
- trial $i '%d' $HOME
trial $i '%L' $HOST
trial $i '%l' $HOSTNAME
trial $i '%n' somehost
+ trial $i '%k' localhost-with-alias
trial $i '%p' $PORT
trial $i '%r' $REMUSER
trial $i '%u' $USER
- trial $i '%%/%C/%i/%h/%d/%L/%l/%n/%p/%r/%u' \
- "%/$HASH/$USERID/127.0.0.1/$HOME/$HOST/$HOSTNAME/somehost/$PORT/$REMUSER/$USER"
+ # We can't specify a full path outside the regress dir, so skip tests
+ # containing %d for UserKnownHostsFile
+ if [ "$i" != "userknownhostsfile" ]; then
+ trial $i '%d' $HOME
+ trial $i '%%/%C/%i/%h/%d/%L/%l/%n/%p/%r/%u' \
+ "%/$HASH/$USERID/127.0.0.1/$HOME/$HOST/$HOSTNAME/somehost/$PORT/$REMUSER/$USER"
+ fi
done
+# Subset of above since we don't expand shell-style variables on anything that
+# runs a command because the shell will expand those.
+for i in controlpath identityagent forwardagent localforward remoteforward \
+ userknownhostsfile; do
+ verbose $tid $i dollar
+ FOO=bar
+ export FOO
+ trial $i '${FOO}' $FOO
+done
+
+
# A subset of options support tilde expansion
for i in controlpath identityagent forwardagent; do
+ verbose $tid $i tilde
trial $i '~' $HOME/
trial $i '~/.ssh' $HOME/.ssh
done
diff --git a/regress/putty-ciphers.sh b/regress/putty-ciphers.sh
index 708c288d7..5b8e25a27 100644
--- a/regress/putty-ciphers.sh
+++ b/regress/putty-ciphers.sh
@@ -1,11 +1,17 @@
-# $OpenBSD: putty-ciphers.sh,v 1.7 2020/01/23 03:35:07 dtucker Exp $
+# $OpenBSD: putty-ciphers.sh,v 1.11 2021/09/01 03:16:06 dtucker Exp $
# Placed in the Public Domain.
tid="putty ciphers"
if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
- echo "putty interop tests not enabled"
- exit 0
+ skip "putty interop tests not enabled"
+fi
+
+# Re-enable ssh-rsa on older PuTTY versions.
+oldver="`${PLINK} --version | awk '/plink: Release/{if ($3<0.76)print "yes"}'`"
+if [ "x$oldver" = "xyes" ]; then
+ echo "HostKeyAlgorithms +ssh-rsa" >> ${OBJ}/sshd_proxy
+ echo "PubkeyAcceptedKeyTypes +ssh-rsa" >> ${OBJ}/sshd_proxy
fi
for c in aes 3des aes128-ctr aes192-ctr aes256-ctr chacha20 ; do
diff --git a/regress/putty-kex.sh b/regress/putty-kex.sh
index 686d0e1af..c75802a06 100644
--- a/regress/putty-kex.sh
+++ b/regress/putty-kex.sh
@@ -1,11 +1,17 @@
-# $OpenBSD: putty-kex.sh,v 1.5 2020/01/23 03:24:38 dtucker Exp $
+# $OpenBSD: putty-kex.sh,v 1.9 2021/09/01 03:16:06 dtucker Exp $
# Placed in the Public Domain.
tid="putty KEX"
if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
- echo "putty interop tests not enabled"
- exit 0
+ skip "putty interop tests not enabled"
+fi
+
+# Re-enable ssh-rsa on older PuTTY versions.
+oldver="`${PLINK} --version | awk '/plink: Release/{if ($3<0.76)print "yes"}'`"
+if [ "x$oldver" = "xyes" ]; then
+ echo "HostKeyAlgorithms +ssh-rsa" >> ${OBJ}/sshd_proxy
+ echo "PubkeyAcceptedKeyTypes +ssh-rsa" >> ${OBJ}/sshd_proxy
fi
for k in dh-gex-sha1 dh-group1-sha1 dh-group14-sha1 ecdh ; do
diff --git a/regress/putty-transfer.sh b/regress/putty-transfer.sh
index 14b41022f..a6864f951 100644
--- a/regress/putty-transfer.sh
+++ b/regress/putty-transfer.sh
@@ -1,11 +1,17 @@
-# $OpenBSD: putty-transfer.sh,v 1.7 2020/01/23 11:19:12 dtucker Exp $
+# $OpenBSD: putty-transfer.sh,v 1.11 2021/09/01 03:16:06 dtucker Exp $
# Placed in the Public Domain.
tid="putty transfer data"
if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
- echo "putty interop tests not enabled"
- exit 0
+ skip "putty interop tests not enabled"
+fi
+
+# Re-enable ssh-rsa on older PuTTY versions.
+oldver="`${PLINK} --version | awk '/plink: Release/{if ($3<0.76)print "yes"}'`"
+if [ "x$oldver" = "xyes" ]; then
+ echo "HostKeyAlgorithms +ssh-rsa" >> ${OBJ}/sshd_proxy
+ echo "PubkeyAcceptedKeyTypes +ssh-rsa" >> ${OBJ}/sshd_proxy
fi
if [ "`${SSH} -Q compression`" = "none" ]; then
diff --git a/regress/reconfigure.sh b/regress/reconfigure.sh
index dd15eddb2..d5b4e9808 100644
--- a/regress/reconfigure.sh
+++ b/regress/reconfigure.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: reconfigure.sh,v 1.6 2017/04/30 23:34:55 djm Exp $
+# $OpenBSD: reconfigure.sh,v 1.9 2021/06/10 09:46:28 dtucker Exp $
# Placed in the Public Domain.
tid="simple connect after reconfigure"
@@ -41,3 +41,25 @@ ${SSH} -F $OBJ/ssh_config somehost true
if [ $? -ne 0 ]; then
fail "ssh connect with failed after reconfigure"
fi
+
+trace "reconfigure with active clients"
+${SSH} -F $OBJ/ssh_config somehost sleep 10 # authenticated client
+${NC} -d 127.0.0.1 $PORT >/dev/null & # unauthenticated client
+PID=`$SUDO cat $PIDFILE`
+rm -f $PIDFILE
+$SUDO kill -HUP $PID
+
+trace "wait for sshd to restart"
+i=0;
+while [ ! -f $PIDFILE -a $i -lt 10 ]; do
+ i=`expr $i + 1`
+ sleep $i
+done
+
+test -f $PIDFILE || fatal "sshd did not restart"
+
+trace "connect after restart with active clients"
+${SSH} -F $OBJ/ssh_config somehost true
+if [ $? -ne 0 ]; then
+ fail "ssh connect with failed after reconfigure"
+fi
diff --git a/regress/rekey.sh b/regress/rekey.sh
index fd6a02cc7..61723cd86 100644
--- a/regress/rekey.sh
+++ b/regress/rekey.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: rekey.sh,v 1.18 2018/04/10 00:14:10 djm Exp $
+# $OpenBSD: rekey.sh,v 1.19 2021/07/19 05:08:54 dtucker Exp $
# Placed in the Public Domain.
tid="rekey"
@@ -71,7 +71,7 @@ for s in 5 10; do
verbose "client rekeylimit default ${s}"
rm -f ${COPY} ${LOG}
${SSH} < ${DATA} -oCompression=no -oRekeyLimit="default $s" -F \
- $OBJ/ssh_proxy somehost "cat >${COPY};sleep $s;sleep 3"
+ $OBJ/ssh_proxy somehost "cat >${COPY};sleep $s;sleep 10"
if [ $? -ne 0 ]; then
fail "ssh failed"
fi
@@ -88,7 +88,7 @@ for s in 5 10; do
verbose "client rekeylimit default ${s} no data"
rm -f ${COPY} ${LOG}
${SSH} -oCompression=no -oRekeyLimit="default $s" -F \
- $OBJ/ssh_proxy somehost "sleep $s;sleep 3"
+ $OBJ/ssh_proxy somehost "sleep $s;sleep 10"
if [ $? -ne 0 ]; then
fail "ssh failed"
fi
@@ -124,7 +124,7 @@ for s in 5 10; do
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
echo "rekeylimit default ${s}" >>$OBJ/sshd_proxy
rm -f ${COPY} ${LOG}
- ${SSH} -oCompression=no -F $OBJ/ssh_proxy somehost "sleep $s;sleep 3"
+ ${SSH} -oCompression=no -F $OBJ/ssh_proxy somehost "sleep $s;sleep 10"
if [ $? -ne 0 ]; then
fail "ssh failed"
fi
diff --git a/regress/scp-uri.sh b/regress/scp-uri.sh
index c03d8bbe0..20ac3c89e 100644
--- a/regress/scp-uri.sh
+++ b/regress/scp-uri.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: scp-uri.sh,v 1.2 2017/12/11 11:41:56 dtucker Exp $
+# $OpenBSD: scp-uri.sh,v 1.4 2021/08/10 03:35:45 djm Exp $
# Placed in the Public Domain.
tid="scp-uri"
@@ -12,7 +12,6 @@ DIR2=${COPY}.dd2
SRC=`dirname ${SCRIPT}`
cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
chmod 755 ${OBJ}/scp-ssh-wrapper.scp
-scpopts="-q -S ${OBJ}/scp-ssh-wrapper.scp"
export SCP # used in scp-ssh-wrapper.scp
scpclean() {
@@ -24,47 +23,55 @@ scpclean() {
cp $OBJ/ssh_config $OBJ/ssh_config.orig
egrep -v '^ +(Port|User) +.*$' $OBJ/ssh_config.orig > $OBJ/ssh_config
-verbose "$tid: simple copy local file to remote file"
-scpclean
-$SCP $scpopts ${DATA} "scp://${USER}@somehost:${PORT}/${COPY}" || fail "copy failed"
-cmp ${DATA} ${COPY} || fail "corrupted copy"
+for mode in scp sftp ; do
+ tag="$tid: $mode mode"
+ if test $mode = scp ; then
+ scpopts="-O -q -S ${OBJ}/scp-ssh-wrapper.scp"
+ else
+ scpopts="-s -D ${SFTPSERVER}"
+ fi
+ verbose "$tag: simple copy local file to remote file"
+ scpclean
+ $SCP $scpopts ${DATA} "scp://${USER}@somehost:${PORT}/${COPY}" || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
-verbose "$tid: simple copy remote file to local file"
-scpclean
-$SCP $scpopts "scp://${USER}@somehost:${PORT}/${DATA}" ${COPY} || fail "copy failed"
-cmp ${DATA} ${COPY} || fail "corrupted copy"
+ verbose "$tag: simple copy remote file to local file"
+ scpclean
+ $SCP $scpopts "scp://${USER}@somehost:${PORT}/${DATA}" ${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
-verbose "$tid: simple copy local file to remote dir"
-scpclean
-cp ${DATA} ${COPY}
-$SCP $scpopts ${COPY} "scp://${USER}@somehost:${PORT}/${DIR}" || fail "copy failed"
-cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+ verbose "$tag: simple copy local file to remote dir"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts ${COPY} "scp://${USER}@somehost:${PORT}/${DIR}" || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-verbose "$tid: simple copy remote file to local dir"
-scpclean
-cp ${DATA} ${COPY}
-$SCP $scpopts "scp://${USER}@somehost:${PORT}/${COPY}" ${DIR} || fail "copy failed"
-cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+ verbose "$tag: simple copy remote file to local dir"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts "scp://${USER}@somehost:${PORT}/${COPY}" ${DIR} || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-verbose "$tid: recursive local dir to remote dir"
-scpclean
-rm -rf ${DIR2}
-cp ${DATA} ${DIR}/copy
-$SCP $scpopts -r ${DIR} "scp://${USER}@somehost:${PORT}/${DIR2}" || fail "copy failed"
-for i in $(cd ${DIR} && echo *); do
- cmp ${DIR}/$i ${DIR2}/$i || fail "corrupted copy"
-done
+ verbose "$tag: recursive local dir to remote dir"
+ scpclean
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -r ${DIR} "scp://${USER}@somehost:${PORT}/${DIR2}" || fail "copy failed"
+ for i in $(cd ${DIR} && echo *); do
+ cmp ${DIR}/$i ${DIR2}/$i || fail "corrupted copy"
+ done
-verbose "$tid: recursive remote dir to local dir"
-scpclean
-rm -rf ${DIR2}
-cp ${DATA} ${DIR}/copy
-$SCP $scpopts -r "scp://${USER}@somehost:${PORT}/${DIR}" ${DIR2} || fail "copy failed"
-for i in $(cd ${DIR} && echo *); do
- cmp ${DIR}/$i ${DIR2}/$i || fail "corrupted copy"
-done
+ verbose "$tag: recursive remote dir to local dir"
+ scpclean
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -r "scp://${USER}@somehost:${PORT}/${DIR}" ${DIR2} || fail "copy failed"
+ for i in $(cd ${DIR} && echo *); do
+ cmp ${DIR}/$i ${DIR2}/$i || fail "corrupted copy"
+ done
-# TODO: scp -3
+ # TODO: scp -3
+done
scpclean
rm -f ${OBJ}/scp-ssh-wrapper.exe
diff --git a/regress/scp.sh b/regress/scp.sh
index 62400efad..358a8df66 100644
--- a/regress/scp.sh
+++ b/regress/scp.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: scp.sh,v 1.11 2019/07/19 03:45:44 djm Exp $
+# $OpenBSD: scp.sh,v 1.13 2021/08/10 03:35:45 djm Exp $
# Placed in the Public Domain.
tid="scp"
@@ -19,7 +19,6 @@ DIR2=${COPY}.dd2
SRC=`dirname ${SCRIPT}`
cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
chmod 755 ${OBJ}/scp-ssh-wrapper.scp
-scpopts="-q -S ${OBJ}/scp-ssh-wrapper.scp"
export SCP # used in scp-ssh-wrapper.scp
scpclean() {
@@ -28,109 +27,117 @@ scpclean() {
chmod 755 ${DIR} ${DIR2}
}
-verbose "$tid: simple copy local file to local file"
-scpclean
-$SCP $scpopts ${DATA} ${COPY} || fail "copy failed"
-cmp ${DATA} ${COPY} || fail "corrupted copy"
-
-verbose "$tid: simple copy local file to remote file"
-scpclean
-$SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed"
-cmp ${DATA} ${COPY} || fail "corrupted copy"
-
-verbose "$tid: simple copy remote file to local file"
-scpclean
-$SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed"
-cmp ${DATA} ${COPY} || fail "corrupted copy"
-
-verbose "$tid: simple copy local file to remote dir"
-scpclean
-cp ${DATA} ${COPY}
-$SCP $scpopts ${COPY} somehost:${DIR} || fail "copy failed"
-cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-
-verbose "$tid: simple copy local file to local dir"
-scpclean
-cp ${DATA} ${COPY}
-$SCP $scpopts ${COPY} ${DIR} || fail "copy failed"
-cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-
-verbose "$tid: simple copy remote file to local dir"
-scpclean
-cp ${DATA} ${COPY}
-$SCP $scpopts somehost:${COPY} ${DIR} || fail "copy failed"
-cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+for mode in scp sftp ; do
+ tag="$tid: $mode mode"
+ if test $mode = scp ; then
+ scpopts="-O -q -S ${OBJ}/scp-ssh-wrapper.scp"
+ else
+ scpopts="-s -D ${SFTPSERVER}"
+ fi
+ verbose "tid: simple copy local file to local file"
+ scpclean
+ $SCP $scpopts ${DATA} ${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
-verbose "$tid: recursive local dir to remote dir"
-scpclean
-rm -rf ${DIR2}
-cp ${DATA} ${DIR}/copy
-$SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed"
-diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: simple copy local file to remote file"
+ scpclean
+ $SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
-verbose "$tid: recursive local dir to local dir"
-scpclean
-rm -rf ${DIR2}
-cp ${DATA} ${DIR}/copy
-$SCP $scpopts -r ${DIR} ${DIR2} || fail "copy failed"
-diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: simple copy remote file to local file"
+ scpclean
+ $SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
-verbose "$tid: recursive remote dir to local dir"
-scpclean
-rm -rf ${DIR2}
-cp ${DATA} ${DIR}/copy
-$SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed"
-diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: simple copy local file to remote dir"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts ${COPY} somehost:${DIR} || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-verbose "$tid: shell metacharacters"
-scpclean
-(cd ${DIR} && \
-touch '`touch metachartest`' && \
-$SCP $scpopts *metachar* ${DIR2} 2>/dev/null; \
-[ ! -f metachartest ] ) || fail "shell metacharacters"
+ verbose "$tag: simple copy local file to local dir"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts ${COPY} ${DIR} || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-if [ ! -z "$SUDO" ]; then
- verbose "$tid: skipped file after scp -p with failed chown+utimes"
+ verbose "$tag: simple copy remote file to local dir"
scpclean
- cp -p ${DATA} ${DIR}/copy
- cp -p ${DATA} ${DIR}/copy2
- cp ${DATA} ${DIR2}/copy
- chmod 660 ${DIR2}/copy
- $SUDO chown root ${DIR2}/copy
- $SCP -p $scpopts somehost:${DIR}/\* ${DIR2} >/dev/null 2>&1
- $SUDO diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
- $SUDO rm ${DIR2}/copy
-fi
+ cp ${DATA} ${COPY}
+ $SCP $scpopts somehost:${COPY} ${DIR} || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
-for i in 0 1 2 3 4 5 6 7; do
- verbose "$tid: disallow bad server #$i"
- SCPTESTMODE=badserver_$i
- export DIR SCPTESTMODE
+ verbose "$tag: recursive local dir to remote dir"
scpclean
- $SCP $scpopts somehost:${DATA} ${DIR} >/dev/null 2>/dev/null
- [ -d {$DIR}/rootpathdir ] && fail "allows dir relative to root dir"
- [ -d ${DIR}/dotpathdir ] && fail "allows dir creation in non-recursive mode"
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed"
+ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: recursive local dir to local dir"
scpclean
- $SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
- [ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir"
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -r ${DIR} ${DIR2} || fail "copy failed"
+ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: recursive remote dir to local dir"
scpclean
- $SCP -pr $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
- [ ! -w ${DIR2} ] && fail "allows target root attribute change"
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed"
+ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ verbose "$tag: shell metacharacters"
scpclean
- $SCP $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
- [ -e ${DIR2}/extrafile ] && fail "allows unauth object creation"
- rm -f ${DIR2}/extrafile
+ (cd ${DIR} && \
+ touch '`touch metachartest`' && \
+ $SCP $scpopts *metachar* ${DIR2} 2>/dev/null; \
+ [ ! -f metachartest ] ) || fail "shell metacharacters"
+
+ if [ ! -z "$SUDO" ]; then
+ verbose "$tag: skipped file after scp -p with failed chown+utimes"
+ scpclean
+ cp -p ${DATA} ${DIR}/copy
+ cp -p ${DATA} ${DIR}/copy2
+ cp ${DATA} ${DIR2}/copy
+ chmod 660 ${DIR2}/copy
+ $SUDO chown root ${DIR2}/copy
+ $SCP -p $scpopts somehost:${DIR}/\* ${DIR2} >/dev/null 2>&1
+ $SUDO diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+ $SUDO rm ${DIR2}/copy
+ fi
+
+ for i in 0 1 2 3 4 5 6 7; do
+ verbose "$tag: disallow bad server #$i"
+ SCPTESTMODE=badserver_$i
+ export DIR SCPTESTMODE
+ scpclean
+ $SCP $scpopts somehost:${DATA} ${DIR} >/dev/null 2>/dev/null
+ [ -d {$DIR}/rootpathdir ] && fail "allows dir relative to root dir"
+ [ -d ${DIR}/dotpathdir ] && fail "allows dir creation in non-recursive mode"
+
+ scpclean
+ $SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+ [ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir"
+
+ scpclean
+ $SCP -pr $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+ [ ! -w ${DIR2} ] && fail "allows target root attribute change"
+
+ scpclean
+ $SCP $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+ [ -e ${DIR2}/extrafile ] && fail "allows unauth object creation"
+ rm -f ${DIR2}/extrafile
+ done
+
+ verbose "$tag: detect non-directory target"
+ scpclean
+ echo a > ${COPY}
+ echo b > ${COPY2}
+ $SCP $scpopts ${DATA} ${COPY} ${COPY2}
+ cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
done
-verbose "$tid: detect non-directory target"
-scpclean
-echo a > ${COPY}
-echo b > ${COPY2}
-$SCP $scpopts ${DATA} ${COPY} ${COPY2}
-cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
-
scpclean
rm -f ${OBJ}/scp-ssh-wrapper.scp
diff --git a/regress/scp3.sh b/regress/scp3.sh
new file mode 100644
index 000000000..f71b15677
--- /dev/null
+++ b/regress/scp3.sh
@@ -0,0 +1,60 @@
+# $OpenBSD: scp3.sh,v 1.3 2021/08/10 03:35:45 djm Exp $
+# Placed in the Public Domain.
+
+tid="scp3"
+
+#set -x
+
+COPY2=${OBJ}/copy2
+DIR=${COPY}.dd
+DIR2=${COPY}.dd2
+
+SRC=`dirname ${SCRIPT}`
+cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
+chmod 755 ${OBJ}/scp-ssh-wrapper.scp
+export SCP # used in scp-ssh-wrapper.scp
+
+scpclean() {
+ rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
+ mkdir ${DIR} ${DIR2}
+ chmod 755 ${DIR} ${DIR2}
+}
+
+for mode in scp sftp ; do
+ scpopts="-F${OBJ}/ssh_proxy -S ${SSH} -q"
+ tag="$tid: $mode mode"
+ if test $mode = scp ; then
+ scpopts="$scpopts -O"
+ else
+ scpopts="-s -D ${SFTPSERVER}"
+ fi
+
+ verbose "$tag: simple copy remote file to remote file"
+ scpclean
+ $SCP $scpopts -3 hostA:${DATA} hostB:${COPY} || fail "copy failed"
+ cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+ verbose "$tag: simple copy remote file to remote dir"
+ scpclean
+ cp ${DATA} ${COPY}
+ $SCP $scpopts -3 hostA:${COPY} hostB:${DIR} || fail "copy failed"
+ cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+
+ verbose "$tag: recursive remote dir to remote dir"
+ scpclean
+ rm -rf ${DIR2}
+ cp ${DATA} ${DIR}/copy
+ $SCP $scpopts -3r hostA:${DIR} hostB:${DIR2} || fail "copy failed"
+ diff -r ${DIR} ${DIR2} || fail "corrupted copy"
+ diff -r ${DIR2} ${DIR} || fail "corrupted copy"
+
+ verbose "$tag: detect non-directory target"
+ scpclean
+ echo a > ${COPY}
+ echo b > ${COPY2}
+ $SCP $scpopts -3 hostA:${DATA} hostA:${COPY} hostB:${COPY2}
+ cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
+done
+
+scpclean
+rm -f ${OBJ}/scp-ssh-wrapper.exe
diff --git a/regress/servcfginclude.sh b/regress/servcfginclude.sh
index b25c8faa8..518a703d1 100644
--- a/regress/servcfginclude.sh
+++ b/regress/servcfginclude.sh
@@ -9,17 +9,17 @@ Match host a
Match host b
Banner /bb
- Include $OBJ/sshd_config.i.*
+ Include $OBJ/sshd_config.i.* # comment
Match host c
- Include $OBJ/sshd_config.i.*
+ Include $OBJ/sshd_config.i.* # comment
Banner /cc
Match host m
Include $OBJ/sshd_config.i.*
Match Host d
- Banner /dd
+ Banner /dd # comment
Match Host e
Banner /ee
@@ -64,7 +64,7 @@ Match host a
Match host b
Banner /bbbb
-Match host c
+Match host c # comment
Banner /cccc
Match Host d
@@ -146,9 +146,43 @@ Include
_EOF
trace "disallow invalid with no argument"
-${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i.x \
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i.x -T \
-C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
fail "sshd allowed Include with no argument"
+# Ensure the Include before any Match block works as expected (bug #3122)
+cat > $OBJ/sshd_config.i << _EOF
+Banner /xx
+HostKey $OBJ/host.ssh-ed25519
+Include $OBJ/sshd_config.i.2
+Match host a
+ Banner /aaaa
+_EOF
+cat > $OBJ/sshd_config.i.2 << _EOF
+Match host a
+ Banner /aa
+_EOF
+
+trace "Include before match blocks"
+trial a /aa "included file before match blocks is properly evaluated"
+
+# Port in included file is correctly interpretted (bug #3169)
+cat > $OBJ/sshd_config.i << _EOF
+Include $OBJ/sshd_config.i.2
+Port 7722
+_EOF
+cat > $OBJ/sshd_config.i.2 << _EOF
+HostKey $OBJ/host.ssh-ed25519
+_EOF
+
+trace "Port after included files"
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i -T \
+ -C "host=x,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out || \
+ fail "failed to parse Port after included files"
+_port=`grep -i '^port ' $OBJ/sshd_config.out | awk '{print $2}'`
+if test "x7722" != "x$_port" ; then
+ fail "The Port in included file was intertepretted wrongly. Expected 7722, got $_port"
+fi
+
# cleanup
rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out
diff --git a/regress/sftp-chroot.sh b/regress/sftp-chroot.sh
index 5acc4d2de..a7766fe63 100644
--- a/regress/sftp-chroot.sh
+++ b/regress/sftp-chroot.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: sftp-chroot.sh,v 1.7 2018/11/22 08:48:32 dtucker Exp $
+# $OpenBSD: sftp-chroot.sh,v 1.8 2021/09/01 00:50:27 dtucker Exp $
# Placed in the Public Domain.
tid="sftp in chroot"
@@ -9,14 +9,11 @@ PRIVDATA=${CHROOT}/${FILENAME}
trap "${SUDO} rm -f ${PRIVDATA}" 0
if [ -z "$SUDO" -a ! -w /var/run ]; then
- echo "need SUDO to create file in /var/run, test won't work without"
- echo SKIPPED
- exit 0
+ skip "need SUDO to create file in /var/run, test won't work without"
fi
if ! $OBJ/check-perm -m chroot "$CHROOT" ; then
- echo "skipped: $CHROOT is unsuitable as ChrootDirectory"
- exit 0
+ skip "$CHROOT is unsuitable as ChrootDirectory"
fi
$SUDO sh -c "echo mekmitastdigoat > $PRIVDATA" || \
diff --git a/regress/sftp-perm.sh b/regress/sftp-perm.sh
index 304ca0ac5..de96a14da 100644
--- a/regress/sftp-perm.sh
+++ b/regress/sftp-perm.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: sftp-perm.sh,v 1.2 2013/10/17 22:00:18 djm Exp $
+# $OpenBSD: sftp-perm.sh,v 1.3 2021/03/31 21:59:26 djm Exp $
# Placed in the Public Domain.
tid="sftp permissions"
@@ -220,13 +220,15 @@ perm_test \
"test ! -d ${COPY}.dd" \
"test -d ${COPY}.dd"
-perm_test \
- "posix-rename" \
- "realpath,stat,lstat" \
- "rename $COPY ${COPY}.1" \
- "touch $COPY" \
- "test -f ${COPY}.1 -a ! -f $COPY" \
- "test -f $COPY -a ! -f ${COPY}.1"
+# Can't readily test this because the client falls back to traditional rename.
+# XXX maybe there is a behaviorial difference we can test for?
+#perm_test \
+# "posix-rename" \
+# "realpath,stat,lstat" \
+# "rename $COPY ${COPY}.1" \
+# "touch $COPY" \
+# "test -f ${COPY}.1 -a ! -f $COPY" \
+# "test -f $COPY -a ! -f ${COPY}.1"
perm_test \
"rename" \
diff --git a/regress/ssh2putty.sh b/regress/ssh2putty.sh
index dcb975d95..9b0831039 100755
--- a/regress/ssh2putty.sh
+++ b/regress/ssh2putty.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# $OpenBSD: ssh2putty.sh,v 1.5 2019/11/21 05:18:47 tb Exp $
+# $OpenBSD: ssh2putty.sh,v 1.9 2021/07/25 12:13:03 dtucker Exp $
if test "x$1" = "x" -o "x$2" = "x" -o "x$3" = "x" ; then
echo "Usage: ssh2putty hostname port ssh-private-key"
@@ -10,6 +10,8 @@ HOST=$1
PORT=$2
KEYFILE=$3
+OPENSSL_BIN="${OPENSSL_BIN:-openssl}"
+
# XXX - support DSA keys too
if grep "BEGIN RSA PRIVATE KEY" $KEYFILE >/dev/null 2>&1 ; then
:
@@ -19,13 +21,13 @@ else
fi
public_exponent=`
- openssl rsa -noout -text -in $KEYFILE | grep ^publicExponent |
+ $OPENSSL_BIN rsa -noout -text -in $KEYFILE | grep ^publicExponent |
sed 's/.*(//;s/).*//'
`
test $? -ne 0 && exit 1
modulus=`
- openssl rsa -noout -modulus -in $KEYFILE | grep ^Modulus= |
+ $OPENSSL_BIN rsa -noout -modulus -in $KEYFILE | grep ^Modulus= |
sed 's/^Modulus=/0x/' | tr A-Z a-z
`
test $? -ne 0 && exit 1
diff --git a/regress/sshcfgparse.sh b/regress/sshcfgparse.sh
index fc72a0a71..504853d32 100644
--- a/regress/sshcfgparse.sh
+++ b/regress/sshcfgparse.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: sshcfgparse.sh,v 1.6 2019/12/21 02:33:07 djm Exp $
+# $OpenBSD: sshcfgparse.sh,v 1.9 2021/06/08 07:05:27 dtucker Exp $
# Placed in the Public Domain.
tid="ssh config parse"
@@ -32,7 +32,7 @@ expect_result_absent() {
verbose "reparse minimal config"
(${SSH} -G -F $OBJ/ssh_config somehost >$OBJ/ssh_config.1 &&
${SSH} -G -F $OBJ/ssh_config.1 somehost >$OBJ/ssh_config.2 &&
- diff $OBJ/ssh_config.1 $OBJ/ssh_config.2) || fail "reparse minimal config"
+ diff $OBJ/ssh_config.1 $OBJ/ssh_config.2) || fail "failed to reparse minimal"
verbose "ssh -W opts"
f=`${SSH} -GF $OBJ/ssh_config host | awk '/exitonforwardfailure/{print $2}'`
@@ -62,34 +62,34 @@ test "$f" = "bar" || fail "user first match -l, expected 'bar' got '$f'"
f=`${SSH} -GF $OBJ/ssh_config baz@host -o user=foo -l bar baz@host | awk '/^user /{print $2}'`
test "$f" = "baz" || fail "user first match user@host, expected 'baz' got '$f'"
-verbose "pubkeyacceptedkeytypes"
+verbose "pubkeyacceptedalgorithms"
# Default set
-f=`${SSH} -GF none host | awk '/^pubkeyacceptedkeytypes /{print $2}'`
+f=`${SSH} -GF none host | awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519" "ssh-ed25519-cert-v01.*"
expect_result_absent "$f" "ssh-dss"
# Explicit override
-f=`${SSH} -GF none -opubkeyacceptedkeytypes=ssh-ed25519 host | \
- awk '/^pubkeyacceptedkeytypes /{print $2}'`
+f=`${SSH} -GF none -opubkeyacceptedalgorithms=ssh-ed25519 host | \
+ awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519"
expect_result_absent "$f" "ssh-ed25519-cert-v01.*" "ssh-dss"
# Removal from default set
-f=`${SSH} -GF none -opubkeyacceptedkeytypes=-ssh-ed25519-cert* host | \
- awk '/^pubkeyacceptedkeytypes /{print $2}'`
+f=`${SSH} -GF none -opubkeyacceptedalgorithms=-ssh-ed25519-cert* host | \
+ awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519"
expect_result_absent "$f" "ssh-ed25519-cert-v01.*" "ssh-dss"
-f=`${SSH} -GF none -opubkeyacceptedkeytypes=-ssh-ed25519 host | \
- awk '/^pubkeyacceptedkeytypes /{print $2}'`
+f=`${SSH} -GF none -opubkeyacceptedalgorithms=-ssh-ed25519 host | \
+ awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519-cert-v01.*"
expect_result_absent "$f" "ssh-ed25519" "ssh-dss"
# Append to default set.
# This is not tested when built !WITH_OPENSSL
if [ "$dsa" = "1" ]; then
- f=`${SSH} -GF none -opubkeyacceptedkeytypes=+ssh-dss-cert* host | \
- awk '/^pubkeyacceptedkeytypes /{print $2}'`
+ f=`${SSH} -GF none -opubkeyacceptedalgorithms=+ssh-dss-cert* host | \
+ awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519" "ssh-dss-cert-v01.*"
expect_result_absent "$f" "ssh-dss"
- f=`${SSH} -GF none -opubkeyacceptedkeytypes=+ssh-dss host | \
- awk '/^pubkeyacceptedkeytypes /{print $2}'`
+ f=`${SSH} -GF none -opubkeyacceptedalgorithms=+ssh-dss host | \
+ awk '/^pubkeyacceptedalgorithms /{print $2}'`
expect_result_present "$f" "ssh-ed25519" "ssh-ed25519-cert-v01.*" "ssh-dss"
expect_result_absent "$f" "ssh-dss-cert-v01.*"
fi
@@ -104,5 +104,16 @@ expect_result_present "$f" "yes"
f=`${SSH} -GF none '-oforwardagent=SSH_AUTH_SOCK.forward' host | awk '/^forwardagent /{print$2}'`
expect_result_present "$f" "SSH_AUTH_SOCK.forward"
+verbose "command line override"
+cat >$OBJ/ssh_config.0 <<EOD
+Host *
+ IPQoS af21 cs1
+ TunnelDevice 1:2
+EOD
+f=`${SSH} -GF $OBJ/ssh_config.0 -oipqos=cs1 host | awk '/^ipqos /{print$2}'`
+expect_result_present "$f" "cs1"
+f=`${SSH} -GF $OBJ/ssh_config.0 -otunneldevice=3:4 host | awk '/^tunneldevice /{print$2}'`
+expect_result_present "$f" "3:4"
+
# cleanup
rm -f $OBJ/ssh_config.[012]
diff --git a/regress/sshfp-connect.sh b/regress/sshfp-connect.sh
new file mode 100644
index 000000000..f78646922
--- /dev/null
+++ b/regress/sshfp-connect.sh
@@ -0,0 +1,66 @@
+# $OpenBSD: sshfp-connect.sh,v 1.4 2021/09/01 00:50:27 dtucker Exp $
+# Placed in the Public Domain.
+
+# This test requires external setup and thus is skipped unless
+# TEST_SSH_SSHFP_DOMAIN is set. It requires:
+# 1) A DNSSEC-enabled domain, which TEST_SSH_SSHFP_DOMAIN points to.
+# 2) A DNSSEC-validating resolver such as unwind(8).
+# 3) The following SSHFP records with fingerprints from rsa_openssh.pub
+# in that domain that are expected to succeed:
+# sshtest: valid sha1 and sha256 fingerprints.
+# sshtest-sha{1,256}, : valid fingerprints for that type only.
+# and the following records that are expected to fail:
+# sshtest-bad: invalid sha1 fingerprint and good sha256 fingerprint
+# sshtest-sha{1,256}-bad: invalid fingerprints for that type only.
+#
+# sshtest IN SSHFP 1 1 99C79CC09F5F81069CC017CDF9552CFC94B3B929
+# sshtest IN SSHFP 1 2 E30D6B9EB7A4DE495324E4D5870B8220577993EA6AF417E8E4A4F1C5 BF01A9B6
+# sshtest-sha1 IN SSHFP 1 1 99C79CC09F5F81069CC017CDF9552CFC94B3B929
+# sshtest-sha256 IN SSHFP 1 2 E30D6B9EB7A4DE495324E4D5870B8220577993EA6AF417E8E4A4F1C5 BF01A9B6
+# sshtest-bad IN SSHFP 1 2 E30D6B9EB7A4DE495324E4D5870B8220577993EA6AF417E8E4A4F1C5 BF01A9B6
+# sshtest-bad IN SSHFP 1 1 99C79CC09F5F81069CC017CDF9552CFC94B3B928
+# sshtest-sha1-bad IN SSHFP 1 1 99D79CC09F5F81069CC017CDF9552CFC94B3B929
+# sshtest-sha256-bad IN SSHFP 1 2 E30D6B9EB7A4DE495324E4D5870B8220577993EA6AF417E8E4A4F1C5 BF01A9B5
+
+tid="sshfp connect"
+
+if ! $SSH -Q key-plain | grep ssh-rsa >/dev/null; then
+ skip "RSA keys not supported."
+elif [ -z "${TEST_SSH_SSHFP_DOMAIN}" ]; then
+ skip "TEST_SSH_SSHFP_DOMAIN not set."
+else
+ # Set RSA host key to match fingerprints above.
+ mv $OBJ/sshd_proxy $OBJ/sshd_proxy.orig
+ $SUDO cp $SRC/rsa_openssh.prv $OBJ/host.ssh-rsa
+ $SUDO chmod 600 $OBJ/host.ssh-rsa
+ sed -e "s|$OBJ/ssh-rsa|$OBJ/host.ssh-rsa|" \
+ $OBJ/sshd_proxy.orig > $OBJ/sshd_proxy
+
+ # Zero out known hosts and key aliases to force use of SSHFP records.
+ > $OBJ/known_hosts
+ mv $OBJ/ssh_proxy $OBJ/ssh_proxy.orig
+ sed -e "/HostKeyAlias.*localhost-with-alias/d" \
+ -e "/Hostname.*127.0.0.1/d" \
+ $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy
+
+ for n in sshtest sshtest-sha1 sshtest-sha256; do
+ trace "sshfp connect $n good fingerprint"
+ host="${n}.dtucker.net"
+ opts="-F $OBJ/ssh_proxy -o VerifyHostKeyDNS=yes "
+ opts="$opts -o HostKeyAlgorithms=rsa-sha2-512,rsa-sha2-256"
+ host="${n}.${TEST_SSH_SSHFP_DOMAIN}"
+ SSH_CONNECTION=`${SSH} $opts $host 'echo $SSH_CONNECTION'`
+ if [ $? -ne 0 ]; then
+ fail "ssh sshfp connect failed"
+ fi
+ if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
+ fail "bad SSH_CONNECTION: $SSH_CONNECTION"
+ fi
+
+ trace "sshfp connect $n bad fingerprint"
+ host="${n}-bad.${TEST_SSH_SSHFP_DOMAIN}"
+ if ${SSH} $opts ${host} true; then
+ fail "sshfp-connect succeeded with bad SSHFP record"
+ fi
+ done
+fi
diff --git a/regress/sshsig.sh b/regress/sshsig.sh
index 1e2f9dda4..fc300a8dc 100644
--- a/regress/sshsig.sh
+++ b/regress/sshsig.sh
@@ -1,4 +1,4 @@
-# $OpenBSD: sshsig.sh,v 1.4 2020/03/13 03:18:45 djm Exp $
+# $OpenBSD: sshsig.sh,v 1.7 2021/08/11 08:55:04 djm Exp $
# Placed in the Public Domain.
tid="sshsig"
@@ -12,12 +12,13 @@ sig_namespace="test-$$"
sig_principal="user-$$@example.com"
# Make a "wrong key"
-${SSHKEYGEN} -t ed25519 -f $OBJ/wrong-key -C "wrong trousers, Grommit" -N '' \
+${SSHKEYGEN} -q -t ed25519 -f $OBJ/wrong-key \
+ -C "wrong trousers, Grommit" -N '' \
|| fatal "couldn't generate key"
WRONG=$OBJ/wrong-key.pub
# Make a CA key.
-${SSHKEYGEN} -t ed25519 -f $OBJ/sigca-key -C "CA" -N '' \
+${SSHKEYGEN} -q -t ed25519 -f $OBJ/sigca-key -C "CA" -N '' \
|| fatal "couldn't generate key"
CA_PRIV=$OBJ/sigca-key
CA_PUB=$OBJ/sigca-key.pub
@@ -63,6 +64,17 @@ for t in $SIGNKEYS; do
< $DATA >/dev/null 2>&1 || \
fail "failed signature for $t key w/ limited namespace"
+ (printf "$sig_principal namespaces=\"$sig_namespace,whatever\" ";
+ cat $pubkey) > $OBJ/allowed_signers
+ ${SSHKEYGEN} -q -Y verify -s $sigfile -n $sig_namespace \
+ -I $sig_principal -f $OBJ/allowed_signers \
+ -O print-pubkey \
+ < $DATA | cut -d' ' -f1-2 > ${OBJ}/${keybase}-fromsig.pub || \
+ fail "failed signature for $t key w/ print-pubkey"
+ cut -d' ' -f1-2 ${OBJ}/${keybase}.pub > ${OBJ}/${keybase}-strip.pub
+ diff -r ${OBJ}/${keybase}-strip.pub ${OBJ}/${keybase}-fromsig.pub || \
+ fail "print-pubkey differs from signature key"
+
# Invalid option
(printf "$sig_principal octopus " ; cat $pubkey) > $OBJ/allowed_signers
${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
@@ -106,6 +118,34 @@ for t in $SIGNKEYS; do
< $DATA >/dev/null 2>&1 && \
fail "accepted signature for $t key with excluded namespace"
+ ( printf "$sig_principal " ;
+ printf "valid-after=\"19800101\",valid-before=\"19900101\" " ;
+ cat $pubkey) > $OBJ/allowed_signers
+
+ # key lifespan valid
+ ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+ -I $sig_principal -f $OBJ/allowed_signers \
+ -Overify-time=19850101 \
+ < $DATA >/dev/null 2>&1 || \
+ fail "failed signature for $t key with valid expiry interval"
+ # key not yet valid
+ ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+ -I $sig_principal -f $OBJ/allowed_signers \
+ -Overify-time=19790101 \
+ < $DATA >/dev/null 2>&1 && \
+ fail "failed signature for $t not-yet-valid key"
+ # key expired
+ ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+ -I $sig_principal -f $OBJ/allowed_signers \
+ -Overify-time=19910101 \
+ < $DATA >/dev/null 2>&1 && \
+ fail "failed signature for $t with expired key"
+ # NB. assumes we're not running this test in the 1980s
+ ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
+ -I $sig_principal -f $OBJ/allowed_signers \
+ < $DATA >/dev/null 2>&1 && \
+ fail "failed signature for $t with expired key"
+
# public key in revoked keys file
cat $pubkey > $OBJ/revoked_keys
(printf "$sig_principal namespaces=\"whatever\" " ;
@@ -116,7 +156,7 @@ for t in $SIGNKEYS; do
< $DATA >/dev/null 2>&1 && \
fail "accepted signature for $t key, but key is in revoked_keys"
- # public key not revoked, but other are present in revoked_keysfile
+ # public key not revoked, but others are present in revoked_keysfile
cat $WRONG > $OBJ/revoked_keys
(printf "$sig_principal " ; cat $pubkey) > $OBJ/allowed_signers
${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
@@ -168,7 +208,7 @@ for t in $SIGNKEYS; do
fail "failed signature for $t cert"
# signing key listed as cert-authority
- (printf "$sig_principal cert-authority" ;
+ (printf "$sig_principal cert-authority " ;
cat $pubkey) > $OBJ/allowed_signers
${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
-I $sig_principal -f $OBJ/allowed_signers \
@@ -183,7 +223,7 @@ for t in $SIGNKEYS; do
fail "accepted signature for $t cert with CA not marked"
# mismatch between cert principal and file
- (printf "josef.k@example.com cert-authority" ;
+ (printf "josef.k@example.com cert-authority " ;
cat $CA_PUB) > $OBJ/allowed_signers
${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \
-I $sig_principal -f $OBJ/allowed_signers \
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
index 5dc975d07..415422ef5 100644
--- a/regress/test-exec.sh
+++ b/regress/test-exec.sh
@@ -1,21 +1,11 @@
-# $OpenBSD: test-exec.sh,v 1.76 2020/04/04 23:04:41 dtucker Exp $
+# $OpenBSD: test-exec.sh,v 1.87 2021/09/01 00:50:27 dtucker Exp $
# Placed in the Public Domain.
#SUDO=sudo
-# Unbreak GNU head(1)
-_POSIX2_VERSION=199209
-export _POSIX2_VERSION
-
-case `uname -s 2>/dev/null` in
-OSF1*)
- BIN_SH=xpg4
- export BIN_SH
- ;;
-CYGWIN*)
- os=cygwin
- ;;
-esac
+if [ ! -x "$TEST_SSH_ELAPSED_TIMES" ]; then
+ STARTTIME=`date '+%s'`
+fi
if [ ! -z "$TEST_SSH_PORT" ]; then
PORT="$TEST_SSH_PORT"
@@ -23,26 +13,6 @@ else
PORT=4242
fi
-# If configure tells us to use a different egrep, create a wrapper function
-# to call it. This means we don't need to change all the tests that depend
-# on a good implementation.
-if test "x${EGREP}" != "x"; then
- egrep ()
-{
- ${EGREP} "$@"
-}
-fi
-
-if [ -x /usr/ucb/whoami ]; then
- USER=`/usr/ucb/whoami`
-elif whoami >/dev/null 2>&1; then
- USER=`whoami`
-elif logname >/dev/null 2>&1; then
- USER=`logname`
-else
- USER=`id -un`
-fi
-
OBJ=$1
if [ "x$OBJ" = "x" ]; then
echo '$OBJ not defined'
@@ -69,6 +39,46 @@ else
fi
unset SSH_AUTH_SOCK
+# Portable-specific settings.
+
+if [ -x /usr/ucb/whoami ]; then
+ USER=`/usr/ucb/whoami`
+elif whoami >/dev/null 2>&1; then
+ USER=`whoami`
+elif logname >/dev/null 2>&1; then
+ USER=`logname`
+else
+ USER=`id -un`
+fi
+if test -z "$LOGNAME"; then
+ LOGNAME="${USER}"
+ export LOGNAME
+fi
+
+# Unbreak GNU head(1)
+_POSIX2_VERSION=199209
+export _POSIX2_VERSION
+
+case `uname -s 2>/dev/null` in
+OSF1*)
+ BIN_SH=xpg4
+ export BIN_SH
+ ;;
+CYGWIN*)
+ os=cygwin
+ ;;
+esac
+
+# If configure tells us to use a different egrep, create a wrapper function
+# to call it. This means we don't need to change all the tests that depend
+# on a good implementation.
+if test "x${EGREP}" != "x"; then
+ egrep ()
+{
+ ${EGREP} "$@"
+}
+fi
+
SRC=`dirname ${SCRIPT}`
# defaults
@@ -92,6 +102,7 @@ CONCH=conch
# Tools used by multiple tests
NC=$OBJ/netcat
+OPENSSL_BIN="${OPENSSL_BIN:-openssl}"
if [ "x$TEST_SSH_SSH" != "x" ]; then
SSH="${TEST_SSH_SSH}"
@@ -147,6 +158,9 @@ fi
if [ "x$TEST_SSH_SK_HELPER" != "x" ]; then
SSH_SK_HELPER="${TEST_SSH_SK_HELPER}"
fi
+if [ "x$TEST_SSH_OPENSSL" != "x" ]; then
+ OPENSSL_BIN="${TEST_SSH_OPENSSL}"
+fi
# Path to sshd must be absolute for rexec
case "$SSHD" in
@@ -242,10 +256,15 @@ fi
>$TEST_REGRESS_LOGFILE
# Create wrapper ssh with logging. We can't just specify "SSH=ssh -E..."
-# because sftp and scp don't handle spaces in arguments.
+# because sftp and scp don't handle spaces in arguments. scp and sftp like
+# to use -q so we remove those to preserve our debug logging. In the rare
+# instance where -q is desirable -qq is equivalent and is not removed.
SSHLOGWRAP=$OBJ/ssh-log-wrapper.sh
-echo "#!/bin/sh" > $SSHLOGWRAP
-echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
+cat >$SSHLOGWRAP <<EOD
+#!/bin/sh
+for i in "\$@";do shift;case "\$i" in -q):;; *) set -- "\$@" "\$i";;esac;done
+exec ${SSH} -E${TEST_SSH_LOGFILE} "\$@"
+EOD
chmod a+rx $OBJ/ssh-log-wrapper.sh
REAL_SSH="$SSH"
@@ -315,10 +334,27 @@ md5 () {
cksum
elif have_prog sum; then
sum
+ elif [ -x ${OPENSSL_BIN} ]; then
+ ${OPENSSL_BIN} md5
else
wc -c
fi
}
+
+# Some platforms don't have hostname at all, but on others uname -n doesn't
+# provide the fully qualified name we need, so in the former case we create
+# our own hostname function.
+if ! have_prog hostname; then
+ hostname() {
+ uname -n
+ }
+fi
+
+make_tmpdir ()
+{
+ SSH_REGRESS_TMP="$($OBJ/mkdtemp openssh-XXXXXXXX)" || \
+ fatal "failed to create temporary directory"
+}
# End of portable specific functions
stop_sshd ()
@@ -352,12 +388,6 @@ stop_sshd ()
fi
}
-make_tmpdir ()
-{
- SSH_REGRESS_TMP="$($OBJ/mkdtemp openssh-XXXXXXXX)" || \
- fatal "failed to create temporary directory"
-}
-
# helper
cleanup ()
{
@@ -372,6 +402,11 @@ cleanup ()
rm -rf "$SSH_REGRESS_TMP"
fi
stop_sshd
+ if [ ! -z "$TEST_SSH_ELAPSED_TIMES" ]; then
+ now=`date '+%s'`
+ elapsed=$(($now - $STARTTIME))
+ echo elapsed $elapsed `basename $SCRIPT .sh`
+ fi
}
start_debug_log ()
@@ -407,12 +442,6 @@ verbose ()
fi
}
-warn ()
-{
- echo "WARNING: $@" >>$TEST_SSH_LOGFILE
- echo "WARNING: $@"
-}
-
fail ()
{
save_debug_log "FAIL: $@"
@@ -433,6 +462,14 @@ fatal ()
exit $RESULT
}
+# Skip remaining tests in script.
+skip ()
+{
+ echo "SKIPPED: $@"
+ cleanup
+ exit $RESULT
+}
+
RESULT=0
PIDFILE=$OBJ/pidfile
@@ -457,7 +494,7 @@ EOF
# but if you aren't careful with permissions then the unit tests could
# be abused to locally escalate privileges.
if [ ! -z "$TEST_SSH_UNSAFE_PERMISSIONS" ]; then
- echo "StrictModes no" >> $OBJ/sshd_config
+ echo " StrictModes no" >> $OBJ/sshd_config
else
# check and warn if excessive permissions are likely to cause failures.
unsafe=""
@@ -485,6 +522,11 @@ EOD
fi
fi
+if [ ! -z "$TEST_SSH_MODULI_FILE" ]; then
+ trace "adding modulifile='$TEST_SSH_MODULI_FILE' to sshd_config"
+ echo " ModuliFile '$TEST_SSH_MODULI_FILE'" >> $OBJ/sshd_config
+fi
+
if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then
trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS"
echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config
@@ -574,7 +616,7 @@ for t in ${SSH_HOSTKEY_TYPES}; do
) >> $OBJ/known_hosts
# use key as host key, too
- $SUDO cp $OBJ/$t $OBJ/host.$t
+ (umask 077; $SUDO cp $OBJ/$t $OBJ/host.$t)
echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
# don't use SUDO for proxy connect
@@ -588,10 +630,11 @@ if test -x "$CONCH" ; then
REGRESS_INTEROP_CONCH=yes
fi
-# If PuTTY is present and we are running a PuTTY test, prepare keys and
-# configuration
+# If PuTTY is present, new enough and we are running a PuTTY test, prepare
+# keys and configuration.
REGRESS_INTEROP_PUTTY=no
-if test -x "$PUTTYGEN" -a -x "$PLINK" ; then
+if test -x "$PUTTYGEN" -a -x "$PLINK" &&
+ "$PUTTYGEN" --help 2>&1 | grep -- --new-passphrase >/dev/null; then
REGRESS_INTEROP_PUTTY=yes
fi
case "$SCRIPT" in
@@ -604,13 +647,13 @@ if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
# Add a PuTTY key to authorized_keys
rm -f ${OBJ}/putty.rsa2
- if ! puttygen -t rsa -o ${OBJ}/putty.rsa2 \
+ if ! "$PUTTYGEN" -t rsa -o ${OBJ}/putty.rsa2 \
--random-device=/dev/urandom \
--new-passphrase /dev/null < /dev/null > /dev/null; then
- echo "Your installed version of PuTTY is too old to support --new-passphrase; trying without (may require manual interaction) ..." >&2
- puttygen -t rsa -o ${OBJ}/putty.rsa2 < /dev/null > /dev/null
+ echo "Your installed version of PuTTY is too old to support --new-passphrase, skipping test" >&2
+ exit 1
fi
- puttygen -O public-openssh ${OBJ}/putty.rsa2 \
+ "$PUTTYGEN" -O public-openssh ${OBJ}/putty.rsa2 \
>> $OBJ/authorized_keys_$USER
# Convert rsa2 host key to PuTTY format
@@ -634,8 +677,6 @@ if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
PUTTYDIR=${OBJ}/.putty
export PUTTYDIR
-
- REGRESS_INTEROP_PUTTY=yes
fi
# create a proxy version of the client config
diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile
index 4e56e1104..4d26b7477 100644
--- a/regress/unittests/Makefile
+++ b/regress/unittests/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.11 2019/04/28 22:53:26 dtucker Exp $
+# $OpenBSD: Makefile,v 1.12 2020/06/19 04:34:21 djm Exp $
REGRESS_FAIL_EARLY?= yes
SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion
-SUBDIR+=authopt misc
+SUBDIR+=authopt misc sshsig
.include <bsd.subdir.mk>
diff --git a/regress/unittests/authopt/Makefile b/regress/unittests/authopt/Makefile
index e8edc7b5f..71a7be5bd 100644
--- a/regress/unittests/authopt/Makefile
+++ b/regress/unittests/authopt/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.5 2020/04/06 09:43:55 dtucker Exp $
+# $OpenBSD: Makefile,v 1.6 2021/01/09 12:24:30 dtucker Exp $
PROG=test_authopt
SRCS=tests.c
@@ -10,7 +10,7 @@ SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c
+SRCS+=addr.c addrmatch.c bitmap.c
SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
SRCS+=ssh-ed25519-sk.c sk-usbhid.c
diff --git a/regress/unittests/authopt/tests.c b/regress/unittests/authopt/tests.c
index 0e8aacb91..9873c09c6 100644
--- a/regress/unittests/authopt/tests.c
+++ b/regress/unittests/authopt/tests.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tests.c,v 1.1 2018/03/03 03:16:17 djm Exp $ */
+/* $OpenBSD: tests.c,v 1.2 2021/07/24 01:54:23 djm Exp $ */
/*
* Regress test for keys options functions.
@@ -6,14 +6,18 @@
* Placed in the public domain
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
+#ifdef HAVE_STDINT_H
#include <stdint.h>
+#endif
#include <stdlib.h>
#include <string.h>
-#include "test_helper.h"
+#include "../test_helper/test_helper.h"
#include "sshkey.h"
#include "authfile.h"
@@ -268,6 +272,8 @@ test_authkeys_parse(void)
} while (0)
ARRAY_TEST("environment", "environment=\"foo=1\",environment=\"bar=2\"",
env, nenv, "foo=1,bar=2");
+ ARRAY_TEST("environment", "environment=\"foo=1\",environment=\"foo=2\"",
+ env, nenv, "foo=1");
ARRAY_TEST("permitopen", "permitopen=\"foo:123\",permitopen=\"bar:*\"",
permitopen, npermitopen, "foo:123,bar:*");
#undef ARRAY_TEST
diff --git a/regress/unittests/conversion/Makefile b/regress/unittests/conversion/Makefile
index 8b2a09cc3..5793c4934 100644
--- a/regress/unittests/conversion/Makefile
+++ b/regress/unittests/conversion/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.2 2017/12/21 00:41:22 djm Exp $
+# $OpenBSD: Makefile,v 1.4 2021/01/09 12:24:30 dtucker Exp $
PROG=test_conversion
SRCS=tests.c
@@ -6,6 +6,7 @@ SRCS=tests.c
# From usr.bin/ssh
SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=atomicio.c misc.c xmalloc.c log.c uidswap.c cleanup.c fatal.c ssherr.c
+SRCS+=match.c addr.c addrmatch.c
REGRESS_TARGETS=run-regress-${PROG}
diff --git a/regress/unittests/conversion/tests.c b/regress/unittests/conversion/tests.c
index ae1154d42..bbdc5f5a7 100644
--- a/regress/unittests/conversion/tests.c
+++ b/regress/unittests/conversion/tests.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tests.c,v 1.2 2019/06/14 04:03:48 djm Exp $ */
+/* $OpenBSD: tests.c,v 1.3 2021/01/18 11:43:34 dtucker Exp $ */
/*
* Regress test for conversions
*
@@ -26,28 +26,28 @@ tests(void)
char buf[1024];
TEST_START("conversion_convtime");
- ASSERT_LONG_EQ(convtime("0"), 0);
- ASSERT_LONG_EQ(convtime("1"), 1);
- ASSERT_LONG_EQ(convtime("1S"), 1);
+ ASSERT_INT_EQ(convtime("0"), 0);
+ ASSERT_INT_EQ(convtime("1"), 1);
+ ASSERT_INT_EQ(convtime("1S"), 1);
/* from the examples in the comment above the function */
- ASSERT_LONG_EQ(convtime("90m"), 5400);
- ASSERT_LONG_EQ(convtime("1h30m"), 5400);
- ASSERT_LONG_EQ(convtime("2d"), 172800);
- ASSERT_LONG_EQ(convtime("1w"), 604800);
+ ASSERT_INT_EQ(convtime("90m"), 5400);
+ ASSERT_INT_EQ(convtime("1h30m"), 5400);
+ ASSERT_INT_EQ(convtime("2d"), 172800);
+ ASSERT_INT_EQ(convtime("1w"), 604800);
/* negative time is not allowed */
- ASSERT_LONG_EQ(convtime("-7"), -1);
- ASSERT_LONG_EQ(convtime("-9d"), -1);
+ ASSERT_INT_EQ(convtime("-7"), -1);
+ ASSERT_INT_EQ(convtime("-9d"), -1);
/* overflow */
- snprintf(buf, sizeof buf, "%llu", (unsigned long long)LONG_MAX);
- ASSERT_LONG_EQ(convtime(buf), -1);
- snprintf(buf, sizeof buf, "%llu", (unsigned long long)LONG_MAX + 1);
- ASSERT_LONG_EQ(convtime(buf), -1);
+ snprintf(buf, sizeof buf, "%llu", (unsigned long long)INT_MAX);
+ ASSERT_INT_EQ(convtime(buf), INT_MAX);
+ snprintf(buf, sizeof buf, "%llu", (unsigned long long)INT_MAX + 1);
+ ASSERT_INT_EQ(convtime(buf), -1);
/* overflow with multiplier */
- snprintf(buf, sizeof buf, "%lluM", (unsigned long long)LONG_MAX/60 + 1);
- ASSERT_LONG_EQ(convtime(buf), -1);
- ASSERT_LONG_EQ(convtime("1000000000000000000000w"), -1);
+ snprintf(buf, sizeof buf, "%lluM", (unsigned long long)INT_MAX/60 + 1);
+ ASSERT_INT_EQ(convtime(buf), -1);
+ ASSERT_INT_EQ(convtime("1000000000000000000000w"), -1);
TEST_DONE();
}
diff --git a/regress/unittests/hostkeys/Makefile b/regress/unittests/hostkeys/Makefile
index d841d96be..9a53423ee 100644
--- a/regress/unittests/hostkeys/Makefile
+++ b/regress/unittests/hostkeys/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.8 2020/04/06 09:43:56 dtucker Exp $
+# $OpenBSD: Makefile,v 1.9 2021/01/09 12:24:30 dtucker Exp $
PROG=test_hostkeys
SRCS=tests.c test_iterate.c
@@ -8,7 +8,7 @@ SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c hostfile.c
+SRCS+=addr.c addrmatch.c bitmap.c hostfile.c
SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
SRCS+=ssh-ed25519-sk.c sk-usbhid.c
diff --git a/regress/unittests/hostkeys/test_iterate.c b/regress/unittests/hostkeys/test_iterate.c
index 5904121ef..a5b17d7e4 100644
--- a/regress/unittests/hostkeys/test_iterate.c
+++ b/regress/unittests/hostkeys/test_iterate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: test_iterate.c,v 1.6 2018/07/16 03:09:59 djm Exp $ */
+/* $OpenBSD: test_iterate.c,v 1.7 2020/12/21 01:31:06 djm Exp $ */
/*
* Regress test for hostfile.h hostkeys_foreach()
*
@@ -194,6 +194,7 @@ struct expected expected_full[] = {
KEY_UNSPEC, /* key type */
NULL, /* deserialised key */
NULL, /* comment */
+ 0, /* note */
} },
{ "dsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -207,6 +208,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #1",
+ 0,
} },
{ "ecdsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -220,6 +222,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #1",
+ 0,
} },
{ "ed25519_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -233,6 +236,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #1",
+ 0,
} },
{ "rsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -246,6 +250,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #1",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -259,6 +264,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -272,6 +278,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ "dsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -285,6 +292,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #2",
+ 0,
} },
{ "ecdsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -298,6 +306,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #2",
+ 0,
} },
{ "ed25519_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -311,6 +320,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #2",
+ 0,
} },
{ "rsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -324,6 +334,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #2",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -337,6 +348,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -350,6 +362,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ "dsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -363,6 +376,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #3",
+ 0,
} },
{ "ecdsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -376,6 +390,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #3",
+ 0,
} },
{ "ed25519_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -389,6 +404,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #3",
+ 0,
} },
{ "rsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
NULL,
@@ -402,6 +418,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #3",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -415,6 +432,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -428,6 +446,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ "dsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
NULL,
@@ -441,6 +460,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #5",
+ 0,
} },
{ "ecdsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
NULL,
@@ -454,6 +474,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #5",
+ 0,
} },
{ "ed25519_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
NULL,
@@ -467,6 +488,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #5",
+ 0,
} },
{ "rsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
NULL,
@@ -480,6 +502,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #5",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -493,6 +516,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
/*
* The next series have each key listed multiple times, as the
@@ -511,6 +535,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #6",
+ 0,
} },
{ "dsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
NULL,
@@ -524,6 +549,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #6",
+ 0,
} },
{ "dsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
NULL,
@@ -537,6 +563,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #6",
+ 0,
} },
{ "ecdsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
NULL,
@@ -550,6 +577,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #6",
+ 0,
} },
{ "ecdsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
NULL,
@@ -563,6 +591,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #6",
+ 0,
} },
{ "ecdsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
NULL,
@@ -576,6 +605,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #6",
+ 0,
} },
{ "ed25519_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
NULL,
@@ -589,6 +619,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #6",
+ 0,
} },
{ "ed25519_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
NULL,
@@ -602,6 +633,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #6",
+ 0,
} },
{ "ed25519_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
NULL,
@@ -615,6 +647,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #6",
+ 0,
} },
{ "rsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
NULL,
@@ -628,6 +661,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #6",
+ 0,
} },
{ "rsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
NULL,
@@ -641,6 +675,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #6",
+ 0,
} },
{ "rsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
NULL,
@@ -654,6 +689,7 @@ struct expected expected_full[] = {
KEY_RSA,
NULL, /* filled at runtime */
"RSA #6",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -667,6 +703,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -680,6 +717,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -693,6 +731,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ "ed25519_4.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -706,6 +745,7 @@ struct expected expected_full[] = {
KEY_ED25519,
NULL, /* filled at runtime */
"ED25519 #4",
+ 0,
} },
{ "ecdsa_4.pub" , -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
NULL,
@@ -719,6 +759,7 @@ struct expected expected_full[] = {
KEY_ECDSA,
NULL, /* filled at runtime */
"ECDSA #4",
+ 0,
} },
{ "dsa_4.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -732,6 +773,7 @@ struct expected expected_full[] = {
KEY_DSA,
NULL, /* filled at runtime */
"DSA #4",
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -745,6 +787,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -758,6 +801,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, 0, 0, 0, -1, {
NULL,
@@ -771,6 +815,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -784,6 +829,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
NULL,
@@ -797,6 +843,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -810,6 +857,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL,
NULL,
+ 0,
} },
{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
NULL,
@@ -823,6 +871,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL, /* filled at runtime */
NULL,
+ 0,
} },
{ NULL, HKF_STATUS_OK, KEY_RSA, HKF_MATCH_HOST, 0, 0, 0, -1, {
NULL,
@@ -836,6 +885,7 @@ struct expected expected_full[] = {
KEY_UNSPEC,
NULL, /* filled at runtime */
NULL,
+ 0,
} },
};
@@ -853,7 +903,7 @@ test_iterate(void)
ctx.flags = HKF_WANT_PARSE_KEY;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, NULL, NULL, ctx.flags), 0);
+ check, &ctx, NULL, NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -864,7 +914,7 @@ test_iterate(void)
ctx.flags = 0;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, NULL, NULL, ctx.flags), 0);
+ check, &ctx, NULL, NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -876,7 +926,7 @@ test_iterate(void)
ctx.match_host_p = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "prometheus.example.com", NULL, ctx.flags), 0);
+ check, &ctx, "prometheus.example.com", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -888,7 +938,7 @@ test_iterate(void)
ctx.match_host_s = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "sisyphus.example.com", NULL, ctx.flags), 0);
+ check, &ctx, "sisyphus.example.com", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -900,7 +950,7 @@ test_iterate(void)
ctx.match_host_p = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "prometheus.example.com", NULL, ctx.flags), 0);
+ check, &ctx, "prometheus.example.com", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -912,7 +962,7 @@ test_iterate(void)
ctx.match_host_s = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "sisyphus.example.com", NULL, ctx.flags), 0);
+ check, &ctx, "sisyphus.example.com", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -923,7 +973,7 @@ test_iterate(void)
ctx.flags = 0;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "actaeon.example.org", NULL, ctx.flags), 0);
+ check, &ctx, "actaeon.example.org", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -934,7 +984,7 @@ test_iterate(void)
ctx.flags = HKF_WANT_MATCH;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "actaeon.example.org", NULL, ctx.flags), 0);
+ check, &ctx, "actaeon.example.org", NULL, ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -946,7 +996,7 @@ test_iterate(void)
ctx.match_ipv4 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -958,7 +1008,8 @@ test_iterate(void)
ctx.match_ipv6 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "2001:db8::1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "2001:db8::1",
+ ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -970,7 +1021,7 @@ test_iterate(void)
ctx.match_ipv4 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -982,7 +1033,8 @@ test_iterate(void)
ctx.match_ipv6 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "2001:db8::1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "2001:db8::1",
+ ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -993,7 +1045,8 @@ test_iterate(void)
ctx.flags = 0;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "192.168.0.1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "192.168.0.1",
+ ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -1004,7 +1057,7 @@ test_iterate(void)
ctx.flags = HKF_WANT_MATCH;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "tiresias.example.org", "::1", ctx.flags), 0);
+ check, &ctx, "tiresias.example.org", "::1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -1017,7 +1070,7 @@ test_iterate(void)
ctx.match_ipv4 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags), 0);
+ check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -1031,7 +1084,7 @@ test_iterate(void)
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
check, &ctx, "prometheus.example.com",
- "2001:db8::1", ctx.flags), 0);
+ "2001:db8::1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -1044,7 +1097,7 @@ test_iterate(void)
ctx.match_ipv4 = 1;
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
- check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags), 0);
+ check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
@@ -1058,7 +1111,7 @@ test_iterate(void)
prepare_expected(expected_full, ctx.nexpected);
ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
check, &ctx, "prometheus.example.com",
- "2001:db8::1", ctx.flags), 0);
+ "2001:db8::1", ctx.flags, 0), 0);
cleanup_expected(expected_full, ctx.nexpected);
TEST_DONE();
}
diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile
index 1c5d68ce8..50b117c07 100644
--- a/regress/unittests/kex/Makefile
+++ b/regress/unittests/kex/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.10 2020/04/06 09:43:56 dtucker Exp $
+# $OpenBSD: Makefile,v 1.12 2021/01/09 12:24:30 dtucker Exp $
PROG=test_kex
SRCS=tests.c test_kex.c
@@ -8,7 +8,7 @@ SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
+SRCS+=addr.c addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c
SRCS+=compat.c ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
SRCS+=ssh-ed25519-sk.c sk-usbhid.c
@@ -23,8 +23,8 @@ SRCS+= kexgexs.c
SRCS+= kexc25519.c
SRCS+= smult_curve25519_ref.c
SRCS+= kexgen.c
-SRCS+= kexsntrup4591761x25519.c
-SRCS+= sntrup4591761.c
+SRCS+= kexsntrup761x25519.c
+SRCS+= sntrup761.c
SRCS+= utf8.c
SRCS+=digest-openssl.c
diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c
index 0e7cd9e07..3bd71a9f4 100644
--- a/regress/unittests/kex/test_kex.c
+++ b/regress/unittests/kex/test_kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: test_kex.c,v 1.4 2019/01/21 12:35:20 djm Exp $ */
+/* $OpenBSD: test_kex.c,v 1.5 2020/12/29 01:02:15 djm Exp $ */
/*
* Regress test KEX
*
@@ -152,6 +152,7 @@ do_kex_with_key(char *kex, int keytype, int bits)
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
+ server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
server2->kex->load_host_public_key = server->kex->load_host_public_key;
server2->kex->load_host_private_key = server->kex->load_host_private_key;
server2->kex->sign = server->kex->sign;
@@ -201,5 +202,8 @@ kex_tests(void)
do_kex("diffie-hellman-group-exchange-sha1");
do_kex("diffie-hellman-group14-sha1");
do_kex("diffie-hellman-group1-sha1");
+# ifdef USE_SNTRUP761X25519
+ do_kex("sntrup761x25519-sha512@openssh.com");
+# endif /* USE_SNTRUP761X25519 */
#endif /* WITH_OPENSSL */
}
diff --git a/regress/unittests/match/Makefile b/regress/unittests/match/Makefile
index 87e75826a..939163d30 100644
--- a/regress/unittests/match/Makefile
+++ b/regress/unittests/match/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.4 2017/12/21 03:01:49 djm Exp $
+# $OpenBSD: Makefile,v 1.5 2021/01/09 12:24:31 dtucker Exp $
PROG=test_match
SRCS=tests.c
@@ -6,7 +6,7 @@ SRCS=tests.c
# From usr.bin/ssh
SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=match.c misc.c log.c uidswap.c fatal.c ssherr.c addrmatch.c xmalloc.c
-SRCS+=cleanup.c atomicio.c
+SRCS+=cleanup.c atomicio.c addr.c
REGRESS_TARGETS=run-regress-${PROG}
diff --git a/regress/unittests/match/tests.c b/regress/unittests/match/tests.c
index 3d9af55f2..4fefaf4f3 100644
--- a/regress/unittests/match/tests.c
+++ b/regress/unittests/match/tests.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tests.c,v 1.5 2018/07/04 13:51:45 djm Exp $ */
+/* $OpenBSD: tests.c,v 1.7 2020/07/15 06:43:16 dtucker Exp $ */
/*
* Regress test for matching functions
*
@@ -105,7 +105,7 @@ tests(void)
#define CHECK_FILTER(string,filter,expected) \
do { \
- char *result = match_filter_blacklist((string), (filter)); \
+ char *result = match_filter_denylist((string), (filter)); \
ASSERT_STRING_EQ(result, expected); \
free(result); \
} while (0)
diff --git a/regress/unittests/misc/Makefile b/regress/unittests/misc/Makefile
index 06e954cb8..656ae44db 100644
--- a/regress/unittests/misc/Makefile
+++ b/regress/unittests/misc/Makefile
@@ -1,12 +1,27 @@
-# $OpenBSD: Makefile,v 1.1 2019/04/28 22:53:26 dtucker Exp $
+# $OpenBSD: Makefile,v 1.7 2021/05/21 03:48:07 djm Exp $
PROG=test_misc
SRCS=tests.c
+SRCS+= test_convtime.c
+SRCS+= test_expand.c
+SRCS+= test_parse.c
+SRCS+= test_argv.c
+SRCS+= test_strdelim.c
# From usr.bin/ssh/Makefile.inc
-SRCS+=sshbuf.c sshbuf-getput-basic.c ssherr.c log.c xmalloc.c misc.c
-# From usr/bin/ssh/sshd/Makefile
-SRCS+=atomicio.c cleanup.c fatal.c
+SRCS+= sshbuf.c
+SRCS+= sshbuf-getput-basic.c
+SRCS+= sshbuf-misc.c
+SRCS+= ssherr.c
+SRCS+= log.c
+SRCS+= xmalloc.c
+SRCS+= misc.c
+SRCS+= match.c
+SRCS+= addr.c
+SRCS+= addrmatch.c
+
+# From usr.bin/ssh/sshd/Makefile
+SRCS+= atomicio.c cleanup.c fatal.c
REGRESS_TARGETS=run-regress-${PROG}
diff --git a/regress/unittests/misc/test_argv.c b/regress/unittests/misc/test_argv.c
new file mode 100644
index 000000000..2cfebf2d9
--- /dev/null
+++ b/regress/unittests/misc/test_argv.c
@@ -0,0 +1,187 @@
+/* $OpenBSD: test_argv.c,v 1.3 2021/06/08 07:40:12 djm Exp $ */
+/*
+ * Regress test for misc argv handling functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_argv(void);
+
+void
+test_argv(void)
+{
+ char **av = NULL;
+ int ac = 0;
+
+#define RESET_ARGV() \
+ do { \
+ argv_free(av, ac); \
+ av = NULL; \
+ ac = -1; \
+ } while (0)
+
+ TEST_START("empty args");
+ ASSERT_INT_EQ(argv_split("", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 0);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_PTR_EQ(av[0], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split(" ", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 0);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_PTR_EQ(av[0], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ TEST_START("trivial args");
+ ASSERT_INT_EQ(argv_split("leamas", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley leamas", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley");
+ ASSERT_STRING_EQ(av[1], "leamas");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ TEST_START("quoted");
+ ASSERT_INT_EQ(argv_split("\"smiley\"", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas \" smiley \"", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas");
+ ASSERT_STRING_EQ(av[1], " smiley ");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"smiley leamas\"", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley\" leamas\" liz", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley leamas");
+ ASSERT_STRING_EQ(av[1], "liz");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ TEST_START("escaped");
+ ASSERT_INT_EQ(argv_split("\\\"smiley\\'", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "\"smiley'");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("'\\'smiley\\\"'", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "'smiley\"");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley\\'s leamas\\'", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley's");
+ ASSERT_STRING_EQ(av[1], "leamas'");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas\\\\smiley", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas\\smiley");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas\\\\ \\\\smiley", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas\\");
+ ASSERT_STRING_EQ(av[1], "\\smiley");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("smiley\\ leamas", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ TEST_START("quoted escaped");
+ ASSERT_INT_EQ(argv_split("'smiley\\ leamas'", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley\\ leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"smiley\\ leamas\"", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "smiley\\ leamas");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ TEST_START("comments");
+ ASSERT_INT_EQ(argv_split("# gold", &ac, &av, 0), 0);
+ ASSERT_INT_EQ(ac, 2);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "#");
+ ASSERT_STRING_EQ(av[1], "gold");
+ ASSERT_PTR_EQ(av[2], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("# gold", &ac, &av, 1), 0);
+ ASSERT_INT_EQ(ac, 0);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_PTR_EQ(av[0], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("leamas#gold", &ac, &av, 1), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas#gold");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"leamas # gold\"", &ac, &av, 1), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas # gold");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ ASSERT_INT_EQ(argv_split("\"leamas\"#gold", &ac, &av, 1), 0);
+ ASSERT_INT_EQ(ac, 1);
+ ASSERT_PTR_NE(av, NULL);
+ ASSERT_STRING_EQ(av[0], "leamas#gold");
+ ASSERT_PTR_EQ(av[1], NULL);
+ RESET_ARGV();
+ TEST_DONE();
+
+ /* XXX test char *argv_assemble(int argc, char **argv) */
+}
diff --git a/regress/unittests/misc/test_convtime.c b/regress/unittests/misc/test_convtime.c
new file mode 100644
index 000000000..8f9be89ff
--- /dev/null
+++ b/regress/unittests/misc/test_convtime.c
@@ -0,0 +1,59 @@
+/* $OpenBSD: test_convtime.c,v 1.1 2021/03/19 03:25:01 djm Exp $ */
+/*
+ * Regress test for misc time conversion functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_convtime(void);
+
+void
+test_convtime(void)
+{
+ char buf[1024];
+
+ TEST_START("misc_convtime");
+ ASSERT_INT_EQ(convtime("0"), 0);
+ ASSERT_INT_EQ(convtime("1"), 1);
+ ASSERT_INT_EQ(convtime("2s"), 2);
+ ASSERT_INT_EQ(convtime("3m"), 180);
+ ASSERT_INT_EQ(convtime("1m30"), 90);
+ ASSERT_INT_EQ(convtime("1m30s"), 90);
+ ASSERT_INT_EQ(convtime("1h1s"), 3601);
+ ASSERT_INT_EQ(convtime("1h30m"), 90 * 60);
+ ASSERT_INT_EQ(convtime("1d"), 24 * 60 * 60);
+ ASSERT_INT_EQ(convtime("1w"), 7 * 24 * 60 * 60);
+ ASSERT_INT_EQ(convtime("1w2d3h4m5"), 788645);
+ ASSERT_INT_EQ(convtime("1w2d3h4m5s"), 788645);
+ /* any negative number or error returns -1 */
+ ASSERT_INT_EQ(convtime("-1"), -1);
+ ASSERT_INT_EQ(convtime(""), -1);
+ ASSERT_INT_EQ(convtime("trout"), -1);
+ ASSERT_INT_EQ(convtime("-77"), -1);
+ /* boundary conditions */
+ snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX);
+ ASSERT_INT_EQ(convtime(buf), INT_MAX);
+ snprintf(buf, sizeof buf, "%llu", (long long unsigned)INT_MAX + 1);
+ ASSERT_INT_EQ(convtime(buf), -1);
+ ASSERT_INT_EQ(convtime("3550w5d3h14m7s"), 2147483647);
+#if INT_MAX == 2147483647
+ ASSERT_INT_EQ(convtime("3550w5d3h14m8s"), -1);
+#endif
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/test_expand.c b/regress/unittests/misc/test_expand.c
new file mode 100644
index 000000000..513c69bce
--- /dev/null
+++ b/regress/unittests/misc/test_expand.c
@@ -0,0 +1,90 @@
+/* $OpenBSD: test_expand.c,v 1.2 2021/04/06 09:07:33 dtucker Exp $ */
+/*
+ * Regress test for misc string expansion functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_expand(void);
+
+void
+test_expand(void)
+{
+ int parseerr;
+ char *ret;
+
+ TEST_START("dollar_expand");
+ ASSERT_INT_EQ(setenv("FOO", "bar", 1), 0);
+ ASSERT_INT_EQ(setenv("BAR", "baz", 1), 0);
+ (void)unsetenv("BAZ");
+#define ASSERT_DOLLAR_EQ(x, y) do { \
+ char *str = dollar_expand(NULL, (x)); \
+ ASSERT_STRING_EQ(str, (y)); \
+ free(str); \
+} while(0)
+ ASSERT_DOLLAR_EQ("${FOO}", "bar");
+ ASSERT_DOLLAR_EQ(" ${FOO}", " bar");
+ ASSERT_DOLLAR_EQ("${FOO} ", "bar ");
+ ASSERT_DOLLAR_EQ(" ${FOO} ", " bar ");
+ ASSERT_DOLLAR_EQ("${FOO}${BAR}", "barbaz");
+ ASSERT_DOLLAR_EQ(" ${FOO} ${BAR}", " bar baz");
+ ASSERT_DOLLAR_EQ("${FOO}${BAR} ", "barbaz ");
+ ASSERT_DOLLAR_EQ(" ${FOO} ${BAR} ", " bar baz ");
+ ASSERT_DOLLAR_EQ("$", "$");
+ ASSERT_DOLLAR_EQ(" $", " $");
+ ASSERT_DOLLAR_EQ("$ ", "$ ");
+
+ /* suppress error messages for error handing tests */
+ log_init("test_misc", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 1);
+ /* error checking, non existent variable */
+ ret = dollar_expand(&parseerr, "a${BAZ}");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ ret = dollar_expand(&parseerr, "${BAZ}b");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ ret = dollar_expand(&parseerr, "a${BAZ}b");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
+ /* invalid format */
+ ret = dollar_expand(&parseerr, "${");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ ret = dollar_expand(&parseerr, "${F");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ ret = dollar_expand(&parseerr, "${FO");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ /* empty variable name */
+ ret = dollar_expand(&parseerr, "${}");
+ ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
+ /* restore loglevel to default */
+ log_init("test_misc", SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 1);
+ TEST_DONE();
+
+ TEST_START("percent_expand");
+ ASSERT_STRING_EQ(percent_expand("%%", "%h", "foo", NULL), "%");
+ ASSERT_STRING_EQ(percent_expand("%h", "h", "foo", NULL), "foo");
+ ASSERT_STRING_EQ(percent_expand("%h ", "h", "foo", NULL), "foo ");
+ ASSERT_STRING_EQ(percent_expand(" %h", "h", "foo", NULL), " foo");
+ ASSERT_STRING_EQ(percent_expand(" %h ", "h", "foo", NULL), " foo ");
+ ASSERT_STRING_EQ(percent_expand(" %a%b ", "a", "foo", "b", "bar", NULL),
+ " foobar ");
+ TEST_DONE();
+
+ TEST_START("percent_dollar_expand");
+ ASSERT_STRING_EQ(percent_dollar_expand("%h${FOO}", "h", "foo", NULL),
+ "foobar");
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/test_parse.c b/regress/unittests/misc/test_parse.c
new file mode 100644
index 000000000..727ff3dea
--- /dev/null
+++ b/regress/unittests/misc/test_parse.c
@@ -0,0 +1,86 @@
+/* $OpenBSD: test_parse.c,v 1.1 2021/03/19 03:25:01 djm Exp $ */
+/*
+ * Regress test for misc user/host/URI parsing functions.
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+
+void test_parse(void);
+
+void
+test_parse(void)
+{
+ int port;
+ char *user, *host, *path;
+
+ TEST_START("misc_parse_user_host_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "some.host");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_ipv4_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@1.22.33.144:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_[ipv4]_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_[ipv4]_nopath");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "1.22.33.144");
+ ASSERT_STRING_EQ(path, ".");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_user_ipv6_path");
+ ASSERT_INT_EQ(parse_user_host_path("someuser@[::1]:some/path",
+ &user, &host, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "::1");
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+
+ TEST_START("misc_parse_uri");
+ ASSERT_INT_EQ(parse_uri("ssh", "ssh://someuser@some.host:22/some/path",
+ &user, &host, &port, &path), 0);
+ ASSERT_STRING_EQ(user, "someuser");
+ ASSERT_STRING_EQ(host, "some.host");
+ ASSERT_INT_EQ(port, 22);
+ ASSERT_STRING_EQ(path, "some/path");
+ free(user); free(host); free(path);
+ TEST_DONE();
+}
diff --git a/regress/unittests/misc/test_strdelim.c b/regress/unittests/misc/test_strdelim.c
new file mode 100644
index 000000000..1d9133d4b
--- /dev/null
+++ b/regress/unittests/misc/test_strdelim.c
@@ -0,0 +1,202 @@
+/* $OpenBSD: test_strdelim.c,v 1.2 2021/05/21 03:59:01 djm Exp $ */
+/*
+ * Regress test for misc strdelim() and co
+ *
+ * Placed in the public domain.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "../test_helper/test_helper.h"
+
+#include "log.h"
+#include "misc.h"
+#include "xmalloc.h"
+
+void test_strdelim(void);
+
+void
+test_strdelim(void)
+{
+ char *orig, *str, *cp;
+
+#define START_STRING(x) orig = str = xstrdup(x)
+#define DONE_STRING() free(orig)
+
+ TEST_START("empty");
+ START_STRING("");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX arguable */
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("whitespace");
+ START_STRING(" ");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX better as NULL */
+ ASSERT_STRING_EQ(str, "");
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("trivial");
+ START_STRING("blob");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob");
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("trivial whitespace");
+ START_STRING("blob ");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob");
+ ASSERT_STRING_EQ(str, "");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX better as NULL */
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("multi");
+ START_STRING("blob1 blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ ASSERT_STRING_EQ(str, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ ASSERT_PTR_EQ(str, NULL);
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("multi whitespace");
+ START_STRING("blob1 blob2 ");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ ASSERT_STRING_EQ(str, "blob2 ");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX better as NULL */
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("multi equals");
+ START_STRING("blob1=blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ ASSERT_STRING_EQ(str, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ ASSERT_PTR_EQ(str, NULL);
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("multi too many equals");
+ START_STRING("blob1==blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1"); /* XXX better returning NULL early */
+ ASSERT_STRING_EQ(str, "=blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "");
+ ASSERT_STRING_EQ(str, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2"); /* XXX should (but can't) reject */
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("multi equals strdelimw");
+ START_STRING("blob1=blob2");
+ cp = strdelimw(&str);
+ ASSERT_STRING_EQ(cp, "blob1=blob2");
+ ASSERT_PTR_EQ(str, NULL);
+ cp = strdelimw(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("quoted");
+ START_STRING("\"blob\"");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX better as NULL */
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("quoted multi");
+ START_STRING("\"blob1\" blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ ASSERT_STRING_EQ(str, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ ASSERT_PTR_EQ(str, NULL);
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("quoted multi reverse");
+ START_STRING("blob1 \"blob2\"");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ ASSERT_STRING_EQ(str, "\"blob2\"");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ ASSERT_STRING_EQ(str, "");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, ""); /* XXX better as NULL */
+ ASSERT_PTR_EQ(str, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("quoted multi middle");
+ START_STRING("blob1 \"blob2\" blob3");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob1");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob2");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob3");
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("badquote");
+ START_STRING("\"blob");
+ cp = strdelim(&str);
+ ASSERT_PTR_EQ(cp, NULL);
+ DONE_STRING();
+ TEST_DONE();
+
+ TEST_START("oops quote");
+ START_STRING("\"blob\\\"");
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "blob\\"); /* XXX wrong */
+ cp = strdelim(&str);
+ ASSERT_STRING_EQ(cp, "");
+ DONE_STRING();
+ TEST_DONE();
+
+}
diff --git a/regress/unittests/misc/tests.c b/regress/unittests/misc/tests.c
index ed775ebbd..b0b7cd433 100644
--- a/regress/unittests/misc/tests.c
+++ b/regress/unittests/misc/tests.c
@@ -1,79 +1,38 @@
-/* $OpenBSD: tests.c,v 1.1 2019/04/28 22:53:26 dtucker Exp $ */
+/* $OpenBSD: tests.c,v 1.7 2021/05/21 03:48:07 djm Exp $ */
/*
* Regress test for misc helper functions.
*
* Placed in the public domain.
*/
+#include "includes.h"
+
#include <sys/types.h>
#include <sys/param.h>
#include <stdio.h>
+#ifdef HAVE_STDINT_H
#include <stdint.h>
+#endif
#include <stdlib.h>
#include <string.h>
-#include "test_helper.h"
+#include "../test_helper/test_helper.h"
+#include "log.h"
#include "misc.h"
+void test_parse(void);
+void test_convtime(void);
+void test_expand(void);
+void test_argv(void);
+void test_strdelim(void);
+
void
tests(void)
{
- int port;
- char *user, *host, *path;
-
- TEST_START("misc_parse_user_host_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "some.host");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_ipv4_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@1.22.33.144:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_[ipv4]_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_[ipv4]_nopath");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "1.22.33.144");
- ASSERT_STRING_EQ(path, ".");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_user_ipv6_path");
- ASSERT_INT_EQ(parse_user_host_path("someuser@[::1]:some/path",
- &user, &host, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "::1");
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
-
- TEST_START("misc_parse_uri");
- ASSERT_INT_EQ(parse_uri("ssh", "ssh://someuser@some.host:22/some/path",
- &user, &host, &port, &path), 0);
- ASSERT_STRING_EQ(user, "someuser");
- ASSERT_STRING_EQ(host, "some.host");
- ASSERT_INT_EQ(port, 22);
- ASSERT_STRING_EQ(path, "some/path");
- free(user); free(host); free(path);
- TEST_DONE();
+ test_parse();
+ test_convtime();
+ test_expand();
+ test_argv();
+ test_strdelim();
}
diff --git a/regress/unittests/sshbuf/Makefile b/regress/unittests/sshbuf/Makefile
index 5f6c4426a..a8ddfaf7e 100644
--- a/regress/unittests/sshbuf/Makefile
+++ b/regress/unittests/sshbuf/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.8 2020/01/26 00:09:50 djm Exp $
+# $OpenBSD: Makefile,v 1.10 2021/01/09 12:24:31 dtucker Exp $
# $OpenBSD: Makefile,v 1.8 2020/01/26 00:09:50 djm Exp $
@@ -15,6 +15,7 @@ SRCS+=test_sshbuf_fixed.c
# From usr.bin/ssh
SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=sshbuf-io.c atomicio.c misc.c xmalloc.c log.c fatal.c ssherr.c cleanup.c
+SRCS+=match.c addr.c addrmatch.c
run-regress-${PROG}: ${PROG}
env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
diff --git a/regress/unittests/sshkey/Makefile b/regress/unittests/sshkey/Makefile
index 29c9b3ba7..d4a892375 100644
--- a/regress/unittests/sshkey/Makefile
+++ b/regress/unittests/sshkey/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.10 2020/04/06 09:43:56 dtucker Exp $
+# $OpenBSD: Makefile,v 1.11 2021/01/09 12:24:31 dtucker Exp $
PROG=test_sshkey
SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c
@@ -8,7 +8,7 @@ SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
-SRCS+=addrmatch.c bitmap.c
+SRCS+=addr.c addrmatch.c bitmap.c
SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
SRCS+=ssh-ed25519-sk.c sk-usbhid.c
diff --git a/regress/unittests/sshkey/mktestdata.sh b/regress/unittests/sshkey/mktestdata.sh
index 8efe6dd03..fcd78e990 100755
--- a/regress/unittests/sshkey/mktestdata.sh
+++ b/regress/unittests/sshkey/mktestdata.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# $OpenBSD: mktestdata.sh,v 1.10 2020/05/01 04:03:14 djm Exp $
+# $OpenBSD: mktestdata.sh,v 1.11 2020/06/19 03:48:49 djm Exp $
PW=mekmitasdigoat
@@ -70,6 +70,15 @@ set -ex
cd testdata
+if [ -f ../../../misc/sk-dummy/sk-dummy.so ] ; then
+ SK_DUMMY=../../../misc/sk-dummy/sk-dummy.so
+elif [ -f ../../../misc/sk-dummy/obj/sk-dummy.so ] ; then
+ SK_DUMMY=../../../misc/sk-dummy/obj/sk-dummy.so
+else
+ echo "Can't find sk-dummy.so" 1>&2
+ exit 1
+fi
+
rm -f rsa_1 dsa_1 ecdsa_1 ed25519_1
rm -f rsa_2 dsa_2 ecdsa_2 ed25519_2
rm -f rsa_n dsa_n ecdsa_n # new-format keys
@@ -81,11 +90,20 @@ ssh-keygen -t rsa -b 1024 -C "RSA test key #1" -N "" -f rsa_1 -m PEM
ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1 -m PEM
ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1 -m PEM
ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1
+ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #1" \
+ -N "" -f ecdsa_sk1
+ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #1" \
+ -N "" -f ed25519_sk1
+
ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2 -m PEM
ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2 -m PEM
ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2 -m PEM
-ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_2
+ssh-keygen -t ed25519 -C "ED25519 test key #2" -N "" -f ed25519_2
+ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #2" \
+ -N "" -f ecdsa_sk2
+ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #2" \
+ -N "" -f ed25519_sk2
cp rsa_1 rsa_n
cp dsa_1 dsa_n
@@ -99,6 +117,8 @@ cp rsa_1 rsa_1_pw
cp dsa_1 dsa_1_pw
cp ecdsa_1 ecdsa_1_pw
cp ed25519_1 ed25519_1_pw
+cp ecdsa_sk1 ecdsa_sk1_pw
+cp ed25519_sk1 ed25519_sk1_pw
cp rsa_1 rsa_n_pw
cp dsa_1 dsa_n_pw
cp ecdsa_1 ecdsa_n_pw
@@ -107,6 +127,8 @@ ssh-keygen -pf rsa_1_pw -m PEM -N "$PW"
ssh-keygen -pf dsa_1_pw -m PEM -N "$PW"
ssh-keygen -pf ecdsa_1_pw -m PEM -N "$PW"
ssh-keygen -pf ed25519_1_pw -N "$PW"
+ssh-keygen -pf ecdsa_sk1_pw -m PEM -N "$PW"
+ssh-keygen -pf ed25519_sk1_pw -N "$PW"
ssh-keygen -pf rsa_n_pw -N "$PW"
ssh-keygen -pf dsa_n_pw -N "$PW"
ssh-keygen -pf ecdsa_n_pw -N "$PW"
@@ -117,7 +139,7 @@ dsa_params dsa_1 dsa_1.param
dsa_params dsa_1 dsa_1.param
ecdsa_params ecdsa_1 ecdsa_1.param
ecdsa_params ecdsa_2 ecdsa_2.param
-# XXX ed25519 params
+# XXX ed25519, *sk params
ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
-Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
@@ -131,6 +153,13 @@ ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
-Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
-V 19990101:20110101 -z 4 ed25519_1.pub
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+ -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+ -V 19990101:20110101 -z 4 ecdsa_sk1.pub
+ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
+ -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
+ -V 19990101:20110101 -z 4 ed25519_sk1.pub
+
# Make a few RSA variant signature too.
cp rsa_1 rsa_1_sha1
@@ -152,30 +181,42 @@ ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
-V 19990101:20110101 -z 7 ecdsa_1.pub
ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
-V 19990101:20110101 -z 8 ed25519_1.pub
+ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
+ -V 19990101:20110101 -z 7 ecdsa_sk1.pub
+ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
+ -V 19990101:20110101 -z 8 ed25519_sk1.pub
ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp
ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp
ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp
ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp
+ssh-keygen -lf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp
+ssh-keygen -lf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp
ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp
ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp
ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp
ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp
+ssh-keygen -lf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp
+ssh-keygen -lf ed25519_sk2 | awk '{print $2}' > ed25519_sk2.fp
+ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp
ssh-keygen -lf dsa_1-cert.pub | awk '{print $2}' > dsa_1-cert.fp
ssh-keygen -lf ecdsa_1-cert.pub | awk '{print $2}' > ecdsa_1-cert.fp
ssh-keygen -lf ed25519_1-cert.pub | awk '{print $2}' > ed25519_1-cert.fp
-ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp
+ssh-keygen -lf ecdsa_sk1-cert.pub | awk '{print $2}' > ecdsa_sk1-cert.fp
+ssh-keygen -lf ed25519_sk1-cert.pub | awk '{print $2}' > ed25519_sk1-cert.fp
ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb
ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb
ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb
ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb
+ssh-keygen -Bf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp.bb
+ssh-keygen -Bf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp.bb
ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb
ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb
ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb
ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb
-
-# XXX Extend ssh-keygen to do detached signatures (better to test/fuzz against)
+ssh-keygen -Bf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp.bb
+ssh-keygen -Bf ed25519_sk2 | awk '{print $2}' > ed25519_sk2.fp.bb
echo "$PW" > pw
diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
index 55627bc12..7d767336e 100644
--- a/regress/unittests/sshkey/test_file.c
+++ b/regress/unittests/sshkey/test_file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: test_file.c,v 1.8 2018/09/13 09:03:20 djm Exp $ */
+/* $OpenBSD: test_file.c,v 1.9 2020/06/19 03:48:49 djm Exp $ */
/*
* Regress test for sshkey.h key management API
*
@@ -422,6 +422,137 @@ sshkey_file_tests(void)
sshkey_free(k1);
+#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
+ TEST_START("parse ECDSA-SK from private");
+ buf = load_file("ecdsa_sk1");
+ ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
+ sshbuf_free(buf);
+ ASSERT_PTR_NE(k1, NULL);
+ ASSERT_INT_EQ(k1->type, KEY_ECDSA_SK);
+ TEST_DONE();
+
+ TEST_START("parse ECDSA-SK from private w/ passphrase");
+ buf = load_file("ecdsa_sk1_pw");
+ ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+ (const char *)sshbuf_ptr(pw), &k2, NULL), 0);
+ sshbuf_free(buf);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("load ECDSA-SK from public");
+ ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_sk1.pub"), &k2,
+ NULL), 0);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("load ECDSA-SK cert");
+ ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_sk1"), &k2), 0);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(k2->type, KEY_ECDSA_SK_CERT);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+ ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+ TEST_DONE();
+
+ TEST_START("ECDSA-SK key hex fingerprint");
+ buf = load_text_file("ecdsa_sk1.fp");
+ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA256, SSH_FP_BASE64);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ TEST_DONE();
+
+ TEST_START("ECDSA-SK cert hex fingerprint");
+ buf = load_text_file("ecdsa_sk1-cert.fp");
+ cp = sshkey_fingerprint(k2, SSH_DIGEST_SHA256, SSH_FP_BASE64);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("ECDSA-SK key bubblebabble fingerprint");
+ buf = load_text_file("ecdsa_sk1.fp.bb");
+ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ TEST_DONE();
+
+ sshkey_free(k1);
+#endif
+
+ TEST_START("parse Ed25519-SK from private");
+ buf = load_file("ed25519_sk1");
+ ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
+ sshbuf_free(buf);
+ ASSERT_PTR_NE(k1, NULL);
+ ASSERT_INT_EQ(k1->type, KEY_ED25519_SK);
+ /* XXX check key contents */
+ TEST_DONE();
+
+ TEST_START("parse Ed25519-SK from private w/ passphrase");
+ buf = load_file("ed25519_sk1_pw");
+ ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
+ (const char *)sshbuf_ptr(pw), &k2, NULL), 0);
+ sshbuf_free(buf);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("load Ed25519-SK from public");
+ ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_sk1.pub"),
+ &k2, NULL), 0);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("load Ed25519-SK cert");
+ ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_sk1"), &k2), 0);
+ ASSERT_PTR_NE(k2, NULL);
+ ASSERT_INT_EQ(k2->type, KEY_ED25519_SK_CERT);
+ ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
+ ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
+ TEST_DONE();
+
+ TEST_START("Ed25519-SK key hex fingerprint");
+ buf = load_text_file("ed25519_sk1.fp");
+ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA256, SSH_FP_BASE64);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ TEST_DONE();
+
+ TEST_START("Ed25519-SK cert hex fingerprint");
+ buf = load_text_file("ed25519_sk1-cert.fp");
+ cp = sshkey_fingerprint(k2, SSH_DIGEST_SHA256, SSH_FP_BASE64);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ sshkey_free(k2);
+ TEST_DONE();
+
+ TEST_START("Ed25519-SK key bubblebabble fingerprint");
+ buf = load_text_file("ed25519_sk1.fp.bb");
+ cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE);
+ ASSERT_PTR_NE(cp, NULL);
+ ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
+ sshbuf_free(buf);
+ free(cp);
+ TEST_DONE();
+
+ sshkey_free(k1);
+
sshbuf_free(pw);
}
diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c
index 359811893..f111446a9 100644
--- a/regress/unittests/sshkey/test_fuzz.c
+++ b/regress/unittests/sshkey/test_fuzz.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: test_fuzz.c,v 1.11 2019/11/25 10:32:35 djm Exp $ */
+/* $OpenBSD: test_fuzz.c,v 1.12 2020/08/27 03:55:22 djm Exp $ */
/*
* Fuzz tests for key parsing
*
@@ -88,7 +88,7 @@ sig_fuzz(struct sshkey *k, const char *sig_alg)
fuzzers |= FUZZ_2_BIT_FLIP;
ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c),
- sig_alg, NULL, 0), 0);
+ sig_alg, NULL, NULL, 0), 0);
ASSERT_SIZE_T_GT(l, 0);
fuzz = fuzz_begin(fuzzers, sig, l);
ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), NULL, 0, NULL), 0);
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c
index 025bb9815..7dc20cc85 100644
--- a/regress/unittests/sshkey/test_sshkey.c
+++ b/regress/unittests/sshkey/test_sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: test_sshkey.c,v 1.20 2019/11/25 10:32:35 djm Exp $ */
+/* $OpenBSD: test_sshkey.c,v 1.21 2020/08/27 03:55:22 djm Exp $ */
/*
* Regress test for sshkey.h key management API
*
@@ -101,7 +101,7 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type,
ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */
ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */
ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen,
- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, 0), 0);
+ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0);
ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
free(sigblob);
@@ -120,7 +120,8 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg,
size_t len;
u_char *sig;
- ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, 0), 0);
+ ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg,
+ NULL, NULL, 0), 0);
ASSERT_SIZE_T_GT(len, 8);
ASSERT_PTR_NE(sig, NULL);
ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
@@ -437,7 +438,7 @@ sshkey_tests(void)
put_opt(k1->cert->extensions, "permit-X11-forwarding", NULL);
put_opt(k1->cert->extensions, "permit-agent-forwarding", NULL);
ASSERT_INT_EQ(sshkey_from_private(k2, &k1->cert->signature_key), 0);
- ASSERT_INT_EQ(sshkey_certify(k1, k2, NULL, NULL), 0);
+ ASSERT_INT_EQ(sshkey_certify(k1, k2, NULL, NULL, NULL), 0);
b = sshbuf_new();
ASSERT_PTR_NE(b, NULL);
ASSERT_INT_EQ(sshkey_putb(k1, b), 0);
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1 b/regress/unittests/sshkey/testdata/ecdsa_sk1
new file mode 100644
index 000000000..b51fb73d6
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1
@@ -0,0 +1,13 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
+RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQRnVT5Cji1D
+Ge2+q2X0vATh6LYnODV+DJrshJorr5GnipW29RfuaDXs0WB6XBej9dOLazVRDjQrtV19Qg
+O6cfkFAAAABHNzaDoAAAGQuPdnP7j3Zz8AAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
+cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEZ1U+Qo4tQxntvqtl9LwE4ei2Jzg1fgya7I
+SaK6+Rp4qVtvUX7mg17NFgelwXo/XTi2s1UQ40K7VdfUIDunH5BQAAAARzc2g6AQAAAOMt
+LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJRURmVFB4YzA0alN5Zk
+Z5NlhoV1pTVlpzcnU5ZFlaSVpTOWhjeVFhcDlVT29Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
+QUVaMVUrUW80dFF4bnR2cXRsOUx3RTRlaTJKemcxZmd5YTdJU2FLNitScDRxVnR2VVg3bW
+cxCjdORmdlbHdYby9YVGkyczFVUTQwSzdWZGZVSUR1bkg1QlE9PQotLS0tLUVORCBFQyBQ
+UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAURUNEU0EtU0sgdGVzdCBrZXkgIzEBAgMEBQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.fp b/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.fp
new file mode 100644
index 000000000..d1921451d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.fp
@@ -0,0 +1 @@
+SHA256:Go7HO0CVPYG+BSDSk9ZUJBKGSrtBExp6obTa9iqzIUo
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.pub b/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.pub
new file mode 100644
index 000000000..9586c61a7
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1-cert.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgE012YoSBE9hEC2FRzblcSx784JNo2A4g611A7I75YMMAAAAIbmlzdHAyNTYAAABBBGdVPkKOLUMZ7b6rZfS8BOHotic4NX4MmuyEmiuvkaeKlbb1F+5oNezRYHpcF6P104trNVEONCu1XX1CA7px+QUAAAAEc3NoOgAAAAAAAAAHAAAAAgAAAAZqdWxpdXMAAAASAAAABWhvc3QxAAAABWhvc3QyAAAAADaLg2AAAAAATR3h4AAAAAAAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEEAlTtPiWUHubBeCys4Xp0QF91dYARpkyqtCnzg10HRS+ZDgkMrSUvPPG+Ge8iqtnB951MBxDq9FqDFIkhQBYXDAAAAGQAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEkAAAAhALY+eXRJjVGnMk38Sm5S+H5CloNq757ypsoxt+WYoadtAAAAIA42/mAhUfLij1GY7wl+OFrI+icB/t4tGiEUZmhx6Foo ECDSA-SK test key #1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1.fp b/regress/unittests/sshkey/testdata/ecdsa_sk1.fp
new file mode 100644
index 000000000..d1921451d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1.fp
@@ -0,0 +1 @@
+SHA256:Go7HO0CVPYG+BSDSk9ZUJBKGSrtBExp6obTa9iqzIUo
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_sk1.fp.bb
new file mode 100644
index 000000000..cb9f4dd0d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1.fp.bb
@@ -0,0 +1 @@
+xovem-sacac-dageg-vovoc-symyz-bozal-cibiv-cyvat-vylyn-romib-hoxax
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1.pub b/regress/unittests/sshkey/testdata/ecdsa_sk1.pub
new file mode 100644
index 000000000..c3b21e02b
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGdVPkKOLUMZ7b6rZfS8BOHotic4NX4MmuyEmiuvkaeKlbb1F+5oNezRYHpcF6P104trNVEONCu1XX1CA7px+QUAAAAEc3NoOg== ECDSA-SK test key #1
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk1_pw b/regress/unittests/sshkey/testdata/ecdsa_sk1_pw
new file mode 100644
index 000000000..4fa23a738
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk1_pw
@@ -0,0 +1,14 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB6vcJVx2
+cPc7yYRROup8VnAAAAEAAAAAEAAAB/AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3Bl
+bnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGdVPkKOLUMZ7b6rZfS8BOHotic4NX4MmuyEmi
+uvkaeKlbb1F+5oNezRYHpcF6P104trNVEONCu1XX1CA7px+QUAAAAEc3NoOgAAAZBrvCxe
+xFz0bvzXwaPhrUHBeNCoZy/wNKDx0kxlxUPuA+lgOvy5l3lT3yxxd0qj5PQB+NTcuz8AAE
+1f7aSWQNZSifox3COsBGoHV9C8i+glcxiBKheAZD+EBnRGjG8kbcaLhuYDW/I39qNe8lHW
+YSDjmvsT55Hy0IAtVRAXizDoXKNdFPTZisC67WyOSJ3ED7Fy4bfT4ApbvhoFTwjikZBEhy
+LOad1sbJa4eT19TsskYfQdnJf8sjAmCMOZY4ZV0FiNW5XZOp8nIal1oyULPfzTAm6oaeFN
+0ImCSU3U8h4wUQ8q/3XvBWtTKycZaoou0AwPoP0QN95Ywte7FHezNPb/n8KD7k0S6h9XAX
+UcBeCe5NHyov/0ZzA2p737hzm3w+MXGOboTQMu8WFXeGh4m7QH2o8ZJdgBhM5JF17uii+Q
+ppGoPWHf33MXwB3wxWmKZ0ua0f9AVLkQ2DfFszUoBJE/kcHRd4kj4Q4FWXeMBN0GoH8gdE
+gRWIlxn2/FAOce/BFPzzdP87H0jwz7SdcuVO1L
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk2 b/regress/unittests/sshkey/testdata/ecdsa_sk2
new file mode 100644
index 000000000..19db5a3f5
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk2
@@ -0,0 +1,13 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
+RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQSTl+SR6rTg
+lOZmcQkCtJ3Pd+lWinezo/gHk4oZdZcTQsmEYs766BlWGuB2Bz3qQRLa6cXsP+4K9kAjAJ
+7zdoFUAAAABHNzaDoAAAGQ1qllJtapZSYAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
+cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEk5fkkeq04JTmZnEJArSdz3fpVop3s6P4B5
+OKGXWXE0LJhGLO+ugZVhrgdgc96kES2unF7D/uCvZAIwCe83aBVAAAAARzc2g6AQAAAOMt
+LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSkxwVkxnSTVvdkRlOW
+VMWmZodCs5WWlMaitnam0rTXhHTXg5NndiRWw0Wm9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
+QUVrNWZra2VxMDRKVG1abkVKQXJTZHozZnBWb3AzczZQNEI1T0tHWFdYRTBMSmhHTE8rdW
+daClZocmdkZ2M5NmtFUzJ1bkY3RC91Q3ZaQUl3Q2U4M2FCVkE9PQotLS0tLUVORCBFQyBQ
+UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAURUNEU0EtU0sgdGVzdCBrZXkgIzIBAgMEBQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk2.fp b/regress/unittests/sshkey/testdata/ecdsa_sk2.fp
new file mode 100644
index 000000000..1bc99ea0d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk2.fp
@@ -0,0 +1 @@
+SHA256:pz8VkgtRY3r50F4zSuzRlmq9c6vPTpJXLKKOgkyUcKE
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk2.fp.bb b/regress/unittests/sshkey/testdata/ecdsa_sk2.fp.bb
new file mode 100644
index 000000000..bfee7658a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk2.fp.bb
@@ -0,0 +1 @@
+xobel-gavur-gorym-pedop-rarob-bunek-gucer-lofeg-syhaf-fylur-zoxix
diff --git a/regress/unittests/sshkey/testdata/ecdsa_sk2.pub b/regress/unittests/sshkey/testdata/ecdsa_sk2.pub
new file mode 100644
index 000000000..2629d9509
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ecdsa_sk2.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBJOX5JHqtOCU5mZxCQK0nc936VaKd7Oj+AeTihl1lxNCyYRizvroGVYa4HYHPepBEtrpxew/7gr2QCMAnvN2gVQAAAAEc3NoOg== ECDSA-SK test key #2
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1 b/regress/unittests/sshkey/testdata/ed25519_sk1
new file mode 100644
index 000000000..4196d9c6a
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
+gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACAhaP5OS1PPOt7uumAvXlDtte9EHbqIT1EZEJ2y
+2v3XMwAAAARzc2g6AAAAuBocY6UaHGOlAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
+9tAAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDoBAAAAQJYq
+lGHhFoA25/q8X/rdTqDAb7dhqs4ehhd/w8x99CwiIWj+TktTzzre7rpgL15Q7bXvRB26iE
+9RGRCdstr91zMAAAAAAAAAFkVEMjU1MTktU0sgdGVzdCBrZXkgIzEBAgM=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1-cert.fp b/regress/unittests/sshkey/testdata/ed25519_sk1-cert.fp
new file mode 100644
index 000000000..a6bb1a99c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1-cert.fp
@@ -0,0 +1 @@
+SHA256:6WZVJ44bqhAWLVP4Ns0TDkoSQSsZo/h2K+mEvOaNFbw
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1-cert.pub b/regress/unittests/sshkey/testdata/ed25519_sk1-cert.pub
new file mode 100644
index 000000000..3c72c268d
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1-cert.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJr7CuMntQKvHoUshx374fJLFEkyxKsEOBA1H6hk5scoAAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDoAAAAAAAAACAAAAAIAAAAGanVsaXVzAAAAEgAAAAVob3N0MQAAAAVob3N0MgAAAAA2i4NgAAAAAE0d4eAAAAAAAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOo/0xneV3iM2qWEo5RUwvUYa2bjff292T5vvuXRomGQAAAAUwAAAAtzc2gtZWQyNTUxOQAAAECgsRGLDh1SI3m66MRp9D2iLP4wabQ0OrDgGidk7LsVn2XZHV5jBZN1RtNfe6PBMeVzfRtGUzOg18sO7H7uU+EC ED25519-SK test key #1
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1.fp b/regress/unittests/sshkey/testdata/ed25519_sk1.fp
new file mode 100644
index 000000000..a6bb1a99c
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1.fp
@@ -0,0 +1 @@
+SHA256:6WZVJ44bqhAWLVP4Ns0TDkoSQSsZo/h2K+mEvOaNFbw
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1.fp.bb b/regress/unittests/sshkey/testdata/ed25519_sk1.fp.bb
new file mode 100644
index 000000000..1bfe20a48
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1.fp.bb
@@ -0,0 +1 @@
+xucac-vusip-tydoz-dudad-nerif-raran-tezun-cogyd-pamoh-bahef-ruxix
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1.pub b/regress/unittests/sshkey/testdata/ed25519_sk1.pub
new file mode 100644
index 000000000..60fe00c39
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDo= ED25519-SK test key #1
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk1_pw b/regress/unittests/sshkey/testdata/ed25519_sk1_pw
new file mode 100644
index 000000000..1c29ff07f
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk1_pw
@@ -0,0 +1,9 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDr5R9Yf/
+ucEh0Ns6c34tcIAAAAEAAAAAEAAABKAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t
+AAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDoAAADA2T6owx
+OSgKz4DvLnS3UJ/renbuew5mbkIWB1/y8xd3y5Usm08iUCAlKxep9dVRQvmyoTrc/7rHOM
+DkokNw+WgKambnlYT/9QfqViZ9iCBtbdmhLM6ksUCgQefvquRyXoJxlWstjXUll6Ru+ZbT
+H//Ss8C1bYtAiXR68OQ+rhDrvQxA9P8J1sGIlkuV3h8YXddSpyBW2Sn0LTHHBXYZo86cXZ
+G4Lnc8aGYm65eqdHgkfRmht3eS8DTdzEBfBNH5Ml
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk2 b/regress/unittests/sshkey/testdata/ed25519_sk2
new file mode 100644
index 000000000..b9b748966
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk2
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
+gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACAV8fu1Sc31QLK2R/zGPdN3ve5xuFvDc7mEAWxb
+aI+YcwAAAARzc2g6AAAAuJCMX5uQjF+bAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
+9tAAAAIBXx+7VJzfVAsrZH/MY903e97nG4W8NzuYQBbFtoj5hzAAAABHNzaDoBAAAAQObE
+PajcKI1W30EKOhBb6u+Fgx464kf7EjnqDSg4l7gAFfH7tUnN9UCytkf8xj3Td73ucbhbw3
+O5hAFsW2iPmHMAAAAAAAAAFkVEMjU1MTktU0sgdGVzdCBrZXkgIzIBAgM=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk2.fp b/regress/unittests/sshkey/testdata/ed25519_sk2.fp
new file mode 100644
index 000000000..1c4369a00
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk2.fp
@@ -0,0 +1 @@
+SHA256:b9BVPS5vuU4yu/FgweojLLg6zbfmBBoWLUgibdxxsoo
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk2.fp.bb b/regress/unittests/sshkey/testdata/ed25519_sk2.fp.bb
new file mode 100644
index 000000000..f5fd9efd8
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk2.fp.bb
@@ -0,0 +1 @@
+xemac-tizim-dihep-supar-zupib-cukak-pasis-febeg-dyguv-hutec-dyxox
diff --git a/regress/unittests/sshkey/testdata/ed25519_sk2.pub b/regress/unittests/sshkey/testdata/ed25519_sk2.pub
new file mode 100644
index 000000000..c7ed9f524
--- /dev/null
+++ b/regress/unittests/sshkey/testdata/ed25519_sk2.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIBXx+7VJzfVAsrZH/MY903e97nG4W8NzuYQBbFtoj5hzAAAABHNzaDo= ED25519-SK test key #2
diff --git a/regress/unittests/sshsig/Makefile b/regress/unittests/sshsig/Makefile
new file mode 100644
index 000000000..65564d1b2
--- /dev/null
+++ b/regress/unittests/sshsig/Makefile
@@ -0,0 +1,25 @@
+# $OpenBSD: Makefile,v 1.2 2021/01/09 12:24:31 dtucker Exp $
+
+PROG=test_sshsig
+SRCS=tests.c
+
+# From usr.bin/ssh
+SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
+SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
+SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
+SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
+SRCS+=addr.c addrmatch.c bitmap.c sshsig.c
+SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
+SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
+SRCS+=ssh-ed25519-sk.c sk-usbhid.c
+
+SRCS+=digest-openssl.c
+#SRCS+=digest-libc.c
+SRCS+=utf8.c
+
+REGRESS_TARGETS=run-regress-${PROG}
+
+run-regress-${PROG}: ${PROG}
+ env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata
+
+.include <bsd.regress.mk>
diff --git a/regress/unittests/sshsig/mktestdata.sh b/regress/unittests/sshsig/mktestdata.sh
new file mode 100755
index 000000000..d2300f9c6
--- /dev/null
+++ b/regress/unittests/sshsig/mktestdata.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# $OpenBSD: mktestdata.sh,v 1.1 2020/06/19 04:32:09 djm Exp $
+
+NAMESPACE=unittest
+
+set -ex
+
+cd testdata
+
+if [ -f ../../../misc/sk-dummy/sk-dummy.so ] ; then
+ SK_DUMMY=../../../misc/sk-dummy/sk-dummy.so
+elif [ -f ../../../misc/sk-dummy/obj/sk-dummy.so ] ; then
+ SK_DUMMY=../../../misc/sk-dummy/obj/sk-dummy.so
+else
+ echo "Can't find sk-dummy.so" 1>&2
+ exit 1
+fi
+
+rm -f signed-data namespace
+rm -f rsa dsa ecdsa ed25519 ecdsa_sk ed25519_sk
+rm -f rsa.sig dsa.sig ecdsa.sig ed25519.sig ecdsa_sk.sig ed25519_sk.sig
+
+printf "This is a test, this is only a test" > signed-data
+printf "$NAMESPACE" > namespace
+
+ssh-keygen -t rsa -C "RSA test" -N "" -f rsa -m PEM
+ssh-keygen -t dsa -C "DSA test" -N "" -f dsa -m PEM
+ssh-keygen -t ecdsa -C "ECDSA test" -N "" -f ecdsa -m PEM
+ssh-keygen -t ed25519 -C "ED25519 test key" -N "" -f ed25519
+ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key" \
+ -N "" -f ecdsa_sk
+ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key" \
+ -N "" -f ed25519_sk
+
+ssh-keygen -Y sign -f rsa -n $NAMESPACE - < signed-data > rsa.sig
+ssh-keygen -Y sign -f dsa -n $NAMESPACE - < signed-data > dsa.sig
+ssh-keygen -Y sign -f ecdsa -n $NAMESPACE - < signed-data > ecdsa.sig
+ssh-keygen -Y sign -f ed25519 -n $NAMESPACE - < signed-data > ed25519.sig
+ssh-keygen -w "$SK_DUMMY" \
+ -Y sign -f ecdsa_sk -n $NAMESPACE - < signed-data > ecdsa_sk.sig
+ssh-keygen -w "$SK_DUMMY" \
+ -Y sign -f ed25519_sk -n $NAMESPACE - < signed-data > ed25519_sk.sig
diff --git a/regress/unittests/sshsig/testdata/dsa b/regress/unittests/sshsig/testdata/dsa
new file mode 100644
index 000000000..7c0063efc
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/dsa
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCXpndQdz2mQVnk+lYOF3nxDT+h6SiJmUvBFhnFWBv8tG4pTOkb
+EwGufLEzGpzjTj+3bjVau7LFt37AFrqs4Num272BWNsYNIjOlGPgq7Xjv32FN00x
+JYh1DoRs1cGGnvohlsWEamGGhTHD1a9ipctPEBV+NrxtZMrl+pO/ZZg8vQIVAKJB
+P3iNYSpSuW74+q4WxLCuK8O3AoGAQldE+BIuxlvoG1IFiWesx0CU+H2KO0SEZc9A
+SX/qjOabh0Fb78ofTlEf9gWHFfat8SvSJQIOPMVlb76Lio8AAMT8Eaa/qQKKYmQL
+dNq4MLhhjxx5KLGt6J2JyFPExCv+qnHYHD59ngtLwKyqGjpSC8LPLktdXn8W/Aad
+Ly1K7+MCgYBsMHBczhSeUh8w7i20CVg4OlNTmfJRVU2tO6OpMxZ/quitRm3hLKSN
+u4xRkvHJwi4LhQtv1SXvLI5gs5P3gCG8tsIAiyCqLinHha63iBdJpqhnV/x/j7dB
+yJr3xJbnmLdWLkkCtNk1Ir1/CuEz+ufAyLGdKWksEAu1UUlb501BkwIVAILIa3Rg
+0h7J9lQpHJphvF3K0M1T
+-----END DSA PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/dsa.pub b/regress/unittests/sshsig/testdata/dsa.pub
new file mode 100644
index 000000000..e77aa7ef4
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/dsa.pub
@@ -0,0 +1 @@
+ssh-dss AAAAB3NzaC1kc3MAAACBAJemd1B3PaZBWeT6Vg4XefENP6HpKImZS8EWGcVYG/y0bilM6RsTAa58sTManONOP7duNVq7ssW3fsAWuqzg26bbvYFY2xg0iM6UY+CrteO/fYU3TTEliHUOhGzVwYae+iGWxYRqYYaFMcPVr2Kly08QFX42vG1kyuX6k79lmDy9AAAAFQCiQT94jWEqUrlu+PquFsSwrivDtwAAAIBCV0T4Ei7GW+gbUgWJZ6zHQJT4fYo7RIRlz0BJf+qM5puHQVvvyh9OUR/2BYcV9q3xK9IlAg48xWVvvouKjwAAxPwRpr+pAopiZAt02rgwuGGPHHkosa3onYnIU8TEK/6qcdgcPn2eC0vArKoaOlILws8uS11efxb8Bp0vLUrv4wAAAIBsMHBczhSeUh8w7i20CVg4OlNTmfJRVU2tO6OpMxZ/quitRm3hLKSNu4xRkvHJwi4LhQtv1SXvLI5gs5P3gCG8tsIAiyCqLinHha63iBdJpqhnV/x/j7dByJr3xJbnmLdWLkkCtNk1Ir1/CuEz+ufAyLGdKWksEAu1UUlb501Bkw== DSA test
diff --git a/regress/unittests/sshsig/testdata/dsa.sig b/regress/unittests/sshsig/testdata/dsa.sig
new file mode 100644
index 000000000..0b14ad6b8
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/dsa.sig
@@ -0,0 +1,13 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAbEAAAAHc3NoLWRzcwAAAIEAl6Z3UHc9pkFZ5PpWDhd58Q0/oekoiZ
+lLwRYZxVgb/LRuKUzpGxMBrnyxMxqc404/t241Wruyxbd+wBa6rODbptu9gVjbGDSIzpRj
+4Ku14799hTdNMSWIdQ6EbNXBhp76IZbFhGphhoUxw9WvYqXLTxAVfja8bWTK5fqTv2WYPL
+0AAAAVAKJBP3iNYSpSuW74+q4WxLCuK8O3AAAAgEJXRPgSLsZb6BtSBYlnrMdAlPh9ijtE
+hGXPQEl/6ozmm4dBW+/KH05RH/YFhxX2rfEr0iUCDjzFZW++i4qPAADE/BGmv6kCimJkC3
+TauDC4YY8ceSixreidichTxMQr/qpx2Bw+fZ4LS8Csqho6UgvCzy5LXV5/FvwGnS8tSu/j
+AAAAgGwwcFzOFJ5SHzDuLbQJWDg6U1OZ8lFVTa07o6kzFn+q6K1GbeEspI27jFGS8cnCLg
+uFC2/VJe8sjmCzk/eAIby2wgCLIKouKceFrreIF0mmqGdX/H+Pt0HImvfElueYt1YuSQK0
+2TUivX8K4TP658DIsZ0paSwQC7VRSVvnTUGTAAAACHVuaXR0ZXN0AAAAAAAAAAZzaGE1MT
+IAAAA3AAAAB3NzaC1kc3MAAAAodi5lr0pqBpO76OY4N1CtfR85BCgZ95qfVjP/e9lToj0q
+lwjSJJXUjw==
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/ecdsa b/regress/unittests/sshsig/testdata/ecdsa
new file mode 100644
index 000000000..55fb440e0
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIFg0ZCSEB5LNeLsXYL25g3kqEWsqh52DR+yNOjyQJqyZoAoGCCqGSM49
+AwEHoUQDQgAE3sud88FV0N8FPspZSV7LWqj6uPPLRZiSsenNuEYAteWPyDgrZsWb
+LzXBuUJucepaCNuW/QWgHBRbrjWj3ERm3A==
+-----END EC PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/ecdsa.pub b/regress/unittests/sshsig/testdata/ecdsa.pub
new file mode 100644
index 000000000..14ec6cf12
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN7LnfPBVdDfBT7KWUley1qo+rjzy0WYkrHpzbhGALXlj8g4K2bFmy81wblCbnHqWgjblv0FoBwUW641o9xEZtw= ECDSA test
diff --git a/regress/unittests/sshsig/testdata/ecdsa.sig b/regress/unittests/sshsig/testdata/ecdsa.sig
new file mode 100644
index 000000000..79781570c
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa.sig
@@ -0,0 +1,7 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAE
+EE3sud88FV0N8FPspZSV7LWqj6uPPLRZiSsenNuEYAteWPyDgrZsWbLzXBuUJucepaCNuW
+/QWgHBRbrjWj3ERm3AAAAAh1bml0dGVzdAAAAAAAAAAGc2hhNTEyAAAAZQAAABNlY2RzYS
+1zaGEyLW5pc3RwMjU2AAAASgAAACEAycVNsTlE+XEZYyYiDxWZlliruf/pPMhEEMR/XLdQ
+a4MAAAAhALQt+5gES7L3uKGptHB6UZQMuZ2WyI0C6FJs4v6AtMIU
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/ecdsa_sk b/regress/unittests/sshsig/testdata/ecdsa_sk
new file mode 100644
index 000000000..62ae44cb0
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa_sk
@@ -0,0 +1,13 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
+RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQSg1WuY0XE+
+VexOsrJsFYuxyVoe6eQ/oXmyz2pEHKZw9moyWehv+Fs7oZWFp3JVmOtybKQ6dvfUZYauQE
+/Ov4PAAAAABHNzaDoAAAGI6iV41+oleNcAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
+cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEoNVrmNFxPlXsTrKybBWLsclaHunkP6F5ss
+9qRBymcPZqMlnob/hbO6GVhadyVZjrcmykOnb31GWGrkBPzr+DwAAAAARzc2g6AQAAAOMt
+LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJQm9oeW54M2tpTFVEeS
+t5UjU3WXBXSU5KektnU1p6WnV2VTljYXFla3JGcW9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
+QUVvTlZybU5GeFBsWHNUckt5YkJXTHNjbGFIdW5rUDZGNXNzOXFSQnltY1BacU1sbm9iL2
+hiCk82R1ZoYWR5VlpqcmNteWtPbmIzMUdXR3JrQlB6citEd0E9PQotLS0tLUVORCBFQyBQ
+UklWQVRFIEtFWS0tLS0tCgAAAAAAAAARRUNEU0EtU0sgdGVzdCBrZXk=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/ecdsa_sk.pub b/regress/unittests/sshsig/testdata/ecdsa_sk.pub
new file mode 100644
index 000000000..385ebf15b
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa_sk.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBKDVa5jRcT5V7E6ysmwVi7HJWh7p5D+hebLPakQcpnD2ajJZ6G/4WzuhlYWnclWY63JspDp299Rlhq5AT86/g8AAAAAEc3NoOg== ECDSA-SK test key
diff --git a/regress/unittests/sshsig/testdata/ecdsa_sk.sig b/regress/unittests/sshsig/testdata/ecdsa_sk.sig
new file mode 100644
index 000000000..86de36063
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa_sk.sig
@@ -0,0 +1,8 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAH8AAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBvcGVuc3NoLmNvbQ
+AAAAhuaXN0cDI1NgAAAEEEoNVrmNFxPlXsTrKybBWLsclaHunkP6F5ss9qRBymcPZqMlno
+b/hbO6GVhadyVZjrcmykOnb31GWGrkBPzr+DwAAAAARzc2g6AAAACHVuaXR0ZXN0AAAAAA
+AAAAZzaGE1MTIAAAB3AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20A
+AABIAAAAIHohGwyy8iKT3zwd1TYA9V/Ioo7h/3zCJUtyq/Qigt/HAAAAIGzidTwq7D/kFa
+7Xjcp/KkdbIs4MfQpfAW/0OciajlpzARI0Vng=
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.pub b/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.pub
new file mode 100644
index 000000000..1597302ce
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.pub
@@ -0,0 +1 @@
+sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBBRGwDjs4HhJFcn4tJ5Gr72KcmRmCS1OirETxaXvnsNApgoOLF1a/7rxldfSMHm73eT1nhHe97W8qicPPEAKDJQAAAALbWluZHJvdC5vcmc=
diff --git a/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.sig b/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.sig
new file mode 100644
index 000000000..4bdd8edc6
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ecdsa_sk_webauthn.sig
@@ -0,0 +1,13 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAIYAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBvcGVuc3NoLmNvbQ
+AAAAhuaXN0cDI1NgAAAEEEFEbAOOzgeEkVyfi0nkavvYpyZGYJLU6KsRPFpe+ew0CmCg4s
+XVr/uvGV19Iwebvd5PWeEd73tbyqJw88QAoMlAAAAAttaW5kcm90Lm9yZwAAAAh1bml0dG
+VzdAAAAAAAAAAGc2hhNTEyAAABhwAAACt3ZWJhdXRobi1zay1lY2RzYS1zaGEyLW5pc3Rw
+MjU2QG9wZW5zc2guY29tAAAASQAAACBj2oMT9tb5wRXe6mdmf4/lgAO8wrgr95ouozwNg4
+itnQAAACEAtU9g5wz3HchUiLfLD6plr9T4TiJ32lVCrATSjpiy0SMBAAADHwAAABdodHRw
+czovL3d3dy5taW5kcm90Lm9yZwAAAON7InR5cGUiOiJ3ZWJhdXRobi5nZXQiLCJjaGFsbG
+VuZ2UiOiJVMU5JVTBsSEFBQUFDSFZ1YVhSMFpYTjBBQUFBQUFBQUFBWnphR0UxTVRJQUFB
+QkFMTHU4WmdjU3h0Nk1zRlV6dWlaZ0c2R3dNZEo5ZDd4ZUU3WW9SSXcwZzlpSEpfd3NGRD
+cxbzRXbHllenZGV0VqYnFRMHFDN0Z3R3Bqa2pVUVAtTmQ2dyIsIm9yaWdpbiI6Imh0dHBz
+Oi8vd3d3Lm1pbmRyb3Qub3JnIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQAAAAA=
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/ed25519 b/regress/unittests/sshsig/testdata/ed25519
new file mode 100644
index 000000000..b44a63d3e
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACCJYs0iDdw0Fe/FTzY1b78I4H/j+R6mz2AmLtwTjHYwBAAAAJjpGas/6Rmr
+PwAAAAtzc2gtZWQyNTUxOQAAACCJYs0iDdw0Fe/FTzY1b78I4H/j+R6mz2AmLtwTjHYwBA
+AAAEDpSKRA1QKW6kYiQftGRWh+H0fNekzYLG6c3bzseoCpEolizSIN3DQV78VPNjVvvwjg
+f+P5HqbPYCYu3BOMdjAEAAAAEEVEMjU1MTkgdGVzdCBrZXkBAgMEBQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/ed25519.pub b/regress/unittests/sshsig/testdata/ed25519.pub
new file mode 100644
index 000000000..b078e4516
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIlizSIN3DQV78VPNjVvvwjgf+P5HqbPYCYu3BOMdjAE ED25519 test key
diff --git a/regress/unittests/sshsig/testdata/ed25519.sig b/regress/unittests/sshsig/testdata/ed25519.sig
new file mode 100644
index 000000000..8e8ff2a8a
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519.sig
@@ -0,0 +1,6 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgiWLNIg3cNBXvxU82NW+/COB/4/
+keps9gJi7cE4x2MAQAAAAIdW5pdHRlc3QAAAAAAAAABnNoYTUxMgAAAFMAAAALc3NoLWVk
+MjU1MTkAAABAihQsbUzuNEFflk5Tw1+H9aLS7tZQk0RG8KW1DtOmDYYnWe3D3UKiG3fcJa
+DNg4vBWp1j1gLRiBMOF+gwYNegDg==
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/ed25519_sk b/regress/unittests/sshsig/testdata/ed25519_sk
new file mode 100644
index 000000000..3a434ecb9
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519_sk
@@ -0,0 +1,8 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
+gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCbGg2F0GK7nOm4pQmAyCuGEjnhvs5q0TtjPbdN
+//+yxwAAAARzc2g6AAAAuBw56jAcOeowAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
+9tAAAAIJsaDYXQYruc6bilCYDIK4YSOeG+zmrRO2M9t03//7LHAAAABHNzaDoBAAAAQFXc
+6dCwWewIk1EBofAouGZApW8+s0XekXenxtb78+x0mxoNhdBiu5zpuKUJgMgrhhI54b7Oat
+E7Yz23Tf//sscAAAAAAAAAE0VEMjU1MTktU0sgdGVzdCBrZXkBAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/ed25519_sk.pub b/regress/unittests/sshsig/testdata/ed25519_sk.pub
new file mode 100644
index 000000000..71051ec3b
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519_sk.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJsaDYXQYruc6bilCYDIK4YSOeG+zmrRO2M9t03//7LHAAAABHNzaDo= ED25519-SK test key
diff --git a/regress/unittests/sshsig/testdata/ed25519_sk.sig b/regress/unittests/sshsig/testdata/ed25519_sk.sig
new file mode 100644
index 000000000..49b6818da
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/ed25519_sk.sig
@@ -0,0 +1,7 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAEoAAAAac2stc3NoLWVkMjU1MTlAb3BlbnNzaC5jb20AAAAgmxoNhd
+Biu5zpuKUJgMgrhhI54b7OatE7Yz23Tf//sscAAAAEc3NoOgAAAAh1bml0dGVzdAAAAAAA
+AAAGc2hhNTEyAAAAZwAAABpzay1zc2gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAAEAi+7eTjW
+/+LQ2M+sCD+KFtH1n7VFFJon/SZFsxODyV8cWTlFKj617Ys1Ur5TV6uaEXQhck8rBA2oQI
+HTPANLIPARI0Vng=
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/namespace b/regress/unittests/sshsig/testdata/namespace
new file mode 100644
index 000000000..1570cd548
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/namespace
@@ -0,0 +1 @@
+unittest \ No newline at end of file
diff --git a/regress/unittests/sshsig/testdata/rsa b/regress/unittests/sshsig/testdata/rsa
new file mode 100644
index 000000000..228fad797
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/rsa
@@ -0,0 +1,39 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIG4wIBAAKCAYEA386lmjRHtJpyj87BrS+ssMmtvc/1SPN0gXTPs9jZ1hYAq98P
+ca3/RYVM4HaSu6COztQJ2ZnZD3Te/XeBnIU2mfuvQEl+DiwisGeNglVyRCi7787f
+PFFfcxzZfDa7EB2qY8S3oaSGZK8QqzuGwmGAImjlQXz6J+HCd/eD/58GoCSSirIE
+CFWCAt+uNrOC/EmgAzsbfcfaIbbVzA40tlgU3hO2J42kddz8CisDTtDKQABFcOaQ
+ZycSfn7HDP+WgXLXXBUI9wVM1Tif1f+9MX08xIsvCvGzo7yLgbbTFLSGr5SkA+tO
+rYuoA7V8fge0id/3pnVtG1Ui3I7vejeAwf0HZqtFeBEnOwkIJFmZeMtFeOVf+4ki
+4h1rDqAvSscNvMtLp6OXpbAATATAuEWEkIQBl1rngnEe0iC9iU9itKMW6qJ4FtIb
+4ACH1EoU1x8vqrFecg2hvqfk5CZBJIbV28JFuGjac3OxBZ17Fqb8ljomUir1GrET
+2z66NMgb5TjDD7BVAgMBAAECggGACfjDGCPMLhfTkuS7bGP7ZcUWoKZrX1y5jCsQ
+NgsraYaBcSb3ITGHdimCS139G68DreN0rOVV7oJejRyOAdNNo367SDn+C9ObmBCF
+FZGJDdBiz0SAXceiYRaf+hDWNNmdheR16hXShxnlvDtivbZqZx4VWN2gp7Y/W+kD
+UJhdSzVV8igMVfK5YDdnI7jL1UHSh1JS3z/QUEA9NmJLpvQ1uc9XBlwhP78g27Me
+6pwS5tccQPOE65OqF0i+xa19nzbmnC940Y34yZeI/UE+PYaO2+asapvOfu/sboBH
+Yb5BuWXVEkSeRWI23SpuZbmfNTtVgiRoRqOvqM4G88LkhYjZ6xpDggxQwJiShiiD
+oWCucs0v3pX8H8/LbGs8l50SGI5nzUqAdZ7/QQucU/GuDiQtampntkLEDgf9KIw/
+SDrtCw1E9fnCWj4Z71IYfepY9bVY6QUEcfTdnDcYSY1Z5tVpzeMHVLeo0lbNVZv9
+2qmPnjjP/IvWbjjwu/PHpUWkUs0BAoHBAPx4YwPXWYgWnesMKXkjAHyO5KA4EyBr
++rcEmOZkZDibC8PKYzIK2ztptuthahVovW20R/QJhJkO5teGZMeGPFq+floCeC5P
+la9CEYGYcTrzgSe1QM9IGMr1vGI1KIWck7VkJ0bkKoY40uIJSVZxnyG9pEpcwYSp
+tnOqA/f5YZUFctWvXUz46OfiLKstXLrcrGIU7YRmLv2rW9twnpJYTzE98g3KpVJ2
+TI1pyvrDTdGeAQUTGCAjpviY6XR5d020vQKBwQDi76wsGLQ3XLI+OAE95Ljo0Mcl
++KdJPVVQPq/VcjKgZQndFloflMRrmgNHme9gmsHOrf8DLZvEDbtT+gbmWslMFZQ9
+om1kR404gfuGmfIYdBdOwWjuBLsZs3pfqDB4Xa3NkxljwOMYTp035n0r2UMFaSy3
+gvpW7fsdPOGAJsqNhSw/JNHcokHeBm7VbV0aD7tSyIghmARb5c98fmrSPbiEo8mP
+ITIZlgbfZCq2KuXY4q16R3QvlpuSwitVobLR/3kCgcEAueH5JM7dQHFGe9RMhL/c
+j9i1Q7GFg4183lsoKBkqIPMmylSsjB+qIihHYS4r6O9g6PCfOXH4iqiKFY0BjlWr
+AjTW2naO/aniz1KZiQ0v8PNv2Eh/Gx4+AtDCjpwM5bLOnfLLaEp9dK1JttqXgGnP
+fAwgdg+s+3votWgr29tkmU+VqPagfxeUg4Xm1XFkoL/wu5Yk+iIx3trXms1kMuOK
+CvtMyBK3fetTmZqWs+Iv3XGz1oSkcqVNPiN3XyY/TJsRAoG/Q17jvjOXTNg4EkCO
+HdHJE1Tnyl4HS7bpnOj/Sl6cqQFV7Ey2dKm1pjwSvS714bgP0UvWaRshIxLwif2w
+DrLlD7FYUPPnhd24Dw6HnW4WcSwFv1uryv2cjgS6T6ueuB0Xe/AvmW2p/Y1ZHz9N
+6baWLwUKQXCg4S3FXui0CVd6yoi+mgBUTSveYguG29WbziDde7YMs+xtXtravhrJ
+m6C3Jql5LQSt2uqvH6KdC3ewxLKGzcZot7f+d5MtSj6216ECgcEA9PGmWeUkhVuW
+Xz2c9iBeHwCtmDso7gVwxNnHqdqirB4f1nDCGbrJS7hz5Ss7/wfzekP2W5if2P6U
+JPUdfykAQgALNn1twAtj1a+UAp31ZWu8JK/Qzt4hLJPBxzMo7MenJq189JmYmDnm
+6D5d9vDLCW15gCZua89GZa8K8V50lYyeHBOHAyzNTfNlnMBkHyP645+nqpuEWzIT
+3mCe2OAbl60o8VvvVUlAQyQ/ObLq37HHEoDu0U/YAnP157cxpa84
+-----END RSA PRIVATE KEY-----
diff --git a/regress/unittests/sshsig/testdata/rsa.pub b/regress/unittests/sshsig/testdata/rsa.pub
new file mode 100644
index 000000000..30142ac0a
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfzqWaNEe0mnKPzsGtL6ywya29z/VI83SBdM+z2NnWFgCr3w9xrf9FhUzgdpK7oI7O1AnZmdkPdN79d4GchTaZ+69ASX4OLCKwZ42CVXJEKLvvzt88UV9zHNl8NrsQHapjxLehpIZkrxCrO4bCYYAiaOVBfPon4cJ394P/nwagJJKKsgQIVYIC3642s4L8SaADOxt9x9ohttXMDjS2WBTeE7YnjaR13PwKKwNO0MpAAEVw5pBnJxJ+fscM/5aBctdcFQj3BUzVOJ/V/70xfTzEiy8K8bOjvIuBttMUtIavlKQD606ti6gDtXx+B7SJ3/emdW0bVSLcju96N4DB/Qdmq0V4ESc7CQgkWZl4y0V45V/7iSLiHWsOoC9Kxw28y0uno5elsABMBMC4RYSQhAGXWueCcR7SIL2JT2K0oxbqongW0hvgAIfUShTXHy+qsV5yDaG+p+TkJkEkhtXbwkW4aNpzc7EFnXsWpvyWOiZSKvUasRPbPro0yBvlOMMPsFU= RSA test
diff --git a/regress/unittests/sshsig/testdata/rsa.sig b/regress/unittests/sshsig/testdata/rsa.sig
new file mode 100644
index 000000000..15a032e01
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/rsa.sig
@@ -0,0 +1,19 @@
+-----BEGIN SSH SIGNATURE-----
+U1NIU0lHAAAAAQAAAZcAAAAHc3NoLXJzYQAAAAMBAAEAAAGBAN/OpZo0R7Saco/Owa0vrL
+DJrb3P9UjzdIF0z7PY2dYWAKvfD3Gt/0WFTOB2krugjs7UCdmZ2Q903v13gZyFNpn7r0BJ
+fg4sIrBnjYJVckQou+/O3zxRX3Mc2Xw2uxAdqmPEt6GkhmSvEKs7hsJhgCJo5UF8+ifhwn
+f3g/+fBqAkkoqyBAhVggLfrjazgvxJoAM7G33H2iG21cwONLZYFN4TtieNpHXc/AorA07Q
+ykAARXDmkGcnEn5+xwz/loFy11wVCPcFTNU4n9X/vTF9PMSLLwrxs6O8i4G20xS0hq+UpA
+PrTq2LqAO1fH4HtInf96Z1bRtVItyO73o3gMH9B2arRXgRJzsJCCRZmXjLRXjlX/uJIuId
+aw6gL0rHDbzLS6ejl6WwAEwEwLhFhJCEAZda54JxHtIgvYlPYrSjFuqieBbSG+AAh9RKFN
+cfL6qxXnINob6n5OQmQSSG1dvCRbho2nNzsQWdexam/JY6JlIq9RqxE9s+ujTIG+U4ww+w
+VQAAAAh1bml0dGVzdAAAAAAAAAAGc2hhNTEyAAABlAAAAAxyc2Etc2hhMi01MTIAAAGACi
+nEpBrQxZi0yOrrT6h98JFfZh0XXioih4fzmvtoV0yOReWClS+otGgXoJyZHcbaKNOjDwSM
+rIkUoX6OUJmtHYP0HRELnKw35m33LdBPXpFGS4tRS7NeSpvc04KtjT6jYXY9FjWy5hcn17
+Sxc/3DnJqLgJBur8acY7FeIzpWmKixPd/dGkEjdWoD9gO6szLczGuQgrOdYmSRL4yKadTJ
+lVjz5OSeKSYYGQy33US2XQassRRNYf4e9byTA3DKvHa/OcTt7lFerea0kZdDpAboqffz7T
+Yaw/hFskAYLIEdTW3aoXBGHSOvu8AkDOtb7qwuxGSQ27pjkDLDNsp1ceCFaCaQ6X83RZuK
+ACv9JUBI5KaSf81e0bs0KezJKkhB9czeZ6dk96qISbgayEBnvhYgXvUDKtHn7HzNlCJKfK
+5ABhNxfGG2CD+NKqcrndwFgS1sQO3hbA84zPQb26ShBovT8ytHBmW1F8ZK4O9Bz61Q6EZK
+vs/u6xP6LUean/so5daa
+-----END SSH SIGNATURE-----
diff --git a/regress/unittests/sshsig/testdata/signed-data b/regress/unittests/sshsig/testdata/signed-data
new file mode 100644
index 000000000..7df4bedd1
--- /dev/null
+++ b/regress/unittests/sshsig/testdata/signed-data
@@ -0,0 +1 @@
+This is a test, this is only a test \ No newline at end of file
diff --git a/regress/unittests/sshsig/tests.c b/regress/unittests/sshsig/tests.c
new file mode 100644
index 000000000..bf59d58d1
--- /dev/null
+++ b/regress/unittests/sshsig/tests.c
@@ -0,0 +1,139 @@
+/* $OpenBSD: tests.c,v 1.2 2020/06/22 06:00:06 djm Exp $ */
+/*
+ * Regress test for sshbuf.h buffer API
+ *
+ * Placed in the public domain
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+#include <openssl/crypto.h>
+
+#include "ssherr.h"
+#include "authfile.h"
+#include "sshkey.h"
+#include "sshbuf.h"
+#include "sshsig.h"
+#include "log.h"
+
+#include "../test_helper/test_helper.h"
+
+static struct sshbuf *
+load_file(const char *name)
+{
+ struct sshbuf *ret = NULL;
+
+ ASSERT_INT_EQ(sshbuf_load_file(test_data_file(name), &ret), 0);
+ ASSERT_PTR_NE(ret, NULL);
+ return ret;
+}
+
+static struct sshkey *
+load_key(const char *name)
+{
+ struct sshkey *ret = NULL;
+ ASSERT_INT_EQ(sshkey_load_public(test_data_file(name), &ret, NULL), 0);
+ ASSERT_PTR_NE(ret, NULL);
+ return ret;
+}
+
+static void
+check_sig(const char *keyname, const char *signame, const struct sshbuf *msg,
+ const char *namespace)
+{
+ struct sshkey *k, *sign_key;
+ struct sshbuf *sig, *rawsig;
+ struct sshkey_sig_details *sig_details;
+
+ k = load_key(keyname);
+ sig = load_file(signame);
+ sign_key = NULL;
+ sig_details = NULL;
+ rawsig = NULL;
+ ASSERT_INT_EQ(sshsig_dearmor(sig, &rawsig), 0);
+ ASSERT_INT_EQ(sshsig_verifyb(rawsig, msg, namespace,
+ &sign_key, &sig_details), 0);
+ ASSERT_INT_EQ(sshkey_equal(k, sign_key), 1);
+ sshkey_free(k);
+ sshkey_free(sign_key);
+ sshkey_sig_details_free(sig_details);
+ sshbuf_free(sig);
+ sshbuf_free(rawsig);
+}
+
+void
+tests(void)
+{
+ struct sshbuf *msg;
+ char *namespace;
+
+#if 0
+ log_init("test_sshsig", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
+#endif
+
+#ifdef WITH_OPENSSL
+ OpenSSL_add_all_algorithms();
+ ERR_load_CRYPTO_strings();
+#endif
+
+ TEST_START("load data");
+ msg = load_file("namespace");
+ namespace = sshbuf_dup_string(msg);
+ ASSERT_PTR_NE(namespace, NULL);
+ sshbuf_free(msg);
+ msg = load_file("signed-data");
+ TEST_DONE();
+
+#ifdef WITH_OPENSSL
+ TEST_START("check RSA signature");
+ check_sig("rsa.pub", "rsa.sig", msg, namespace);
+ TEST_DONE();
+
+ TEST_START("check DSA signature");
+ check_sig("dsa.pub", "dsa.sig", msg, namespace);
+ TEST_DONE();
+
+#ifdef OPENSSL_HAS_ECC
+ TEST_START("check ECDSA signature");
+ check_sig("ecdsa.pub", "ecdsa.sig", msg, namespace);
+ TEST_DONE();
+#endif
+#endif
+
+ TEST_START("check ED25519 signature");
+ check_sig("ed25519.pub", "ed25519.sig", msg, namespace);
+ TEST_DONE();
+
+#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
+ TEST_START("check ECDSA-SK signature");
+ check_sig("ecdsa_sk.pub", "ecdsa_sk.sig", msg, namespace);
+ TEST_DONE();
+#endif
+
+ TEST_START("check ED25519-SK signature");
+ check_sig("ed25519_sk.pub", "ed25519_sk.sig", msg, namespace);
+ TEST_DONE();
+
+#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
+ TEST_START("check ECDSA-SK webauthn signature");
+ check_sig("ecdsa_sk_webauthn.pub", "ecdsa_sk_webauthn.sig",
+ msg, namespace);
+ TEST_DONE();
+#endif
+
+ sshbuf_free(msg);
+ free(namespace);
+}
diff --git a/regress/unittests/sshsig/webauthn.html b/regress/unittests/sshsig/webauthn.html
new file mode 100644
index 000000000..1869c8b37
--- /dev/null
+++ b/regress/unittests/sshsig/webauthn.html
@@ -0,0 +1,766 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<title>webauthn test</title>
+</head>
+<body onload="init()">
+<h1>webauthn test</h1>
+<p>
+This is a demo/test page for generating FIDO keys and signatures in SSH
+formats. The page initially displays a form to generate a FIDO key and
+convert it to a SSH public key.
+</p>
+<p>
+Once a key has been generated, an additional form will be displayed to
+allow signing of data using the just-generated key. The data may be signed
+as either a raw SSH signature or wrapped in a sshsig message (the latter is
+easier to test using command-line tools.
+</p>
+<p>
+Lots of debugging is printed along the way.
+</p>
+<h2>Enroll</h2>
+<span id="error" style="color: #800; font-weight: bold; font-size: 150%;"></span>
+<form id="enrollform">
+<table>
+<tr>
+<td><b>Username:</b></td>
+<td><input id="username" type="text" size="20" name="user" value="test" /></td>
+</tr>
+<tr><td></td><td><input id="assertsubmit" type="submit" value="submit" /></td></tr>
+</table>
+</form>
+<span id="enrollresult" style="visibility: hidden;">
+<h2>clientData</h2>
+<pre id="enrollresultjson" style="color: #008; font-family: monospace;"></pre>
+<h2>attestationObject raw</h2>
+<pre id="enrollresultraw" style="color: #008; font-family: monospace;"></pre>
+<h2>attestationObject</h2>
+<pre id="enrollresultattestobj" style="color: #008; font-family: monospace;"></pre>
+<h2>key handle</h2>
+<pre id="keyhandle" style="color: #008; font-family: monospace;"></pre>
+<h2>authData raw</h2>
+<pre id="enrollresultauthdataraw" style="color: #008; font-family: monospace;"></pre>
+<h2>authData</h2>
+<pre id="enrollresultauthdata" style="color: #008; font-family: monospace;"></pre>
+<h2>SSH pubkey blob</h2>
+<pre id="enrollresultpkblob" style="color: #008; font-family: monospace;"></pre>
+<h2>SSH pubkey string</h2>
+<pre id="enrollresultpk" style="color: #008; font-family: monospace;"></pre>
+<h2>SSH private key string</h2>
+<pre id="enrollresultprivkey" style="color: #008; font-family: monospace;"></pre>
+</span>
+<span id="assertsection" style="visibility: hidden;">
+<h2>Assert</h2>
+<form id="assertform">
+<span id="asserterror" style="color: #800; font-weight: bold;"></span>
+<table>
+<tr>
+<td><b>Data to sign:</b></td>
+<td><input id="message" type="text" size="20" name="message" value="test" /></td>
+</tr>
+<tr>
+<td><input id="message_sshsig" type="checkbox" checked /> use sshsig format</td>
+</tr>
+<tr>
+<td><b>Signature namespace:</b></td>
+<td><input id="message_namespace" type="text" size="20" name="namespace" value="test" /></td>
+</tr>
+<tr><td></td><td><input type="submit" value="submit" /></td></tr>
+</table>
+</form>
+</span>
+<span id="assertresult" style="visibility: hidden;">
+<h2>clientData</h2>
+<pre id="assertresultjson" style="color: #008; font-family: monospace;"></pre>
+<h2>signature raw</h2>
+<pre id="assertresultsigraw" style="color: #008; font-family: monospace;"></pre>
+<h2>authenticatorData raw</h2>
+<pre id="assertresultauthdataraw" style="color: #008; font-family: monospace;"></pre>
+<h2>authenticatorData</h2>
+<pre id="assertresultauthdata" style="color: #008; font-family: monospace;"></pre>
+<h2>signature in SSH format</h2>
+<pre id="assertresultsshsigraw" style="color: #008; font-family: monospace;"></pre>
+<h2>signature in SSH format (base64 encoded)</h2>
+<pre id="assertresultsshsigb64" style="color: #008; font-family: monospace;"></pre>
+</span>
+</body>
+<script>
+// ------------------------------------------------------------------
+// a crappy CBOR decoder - 20200401 djm@openbsd.org
+
+var CBORDecode = function(buffer) {
+ this.buf = buffer
+ this.v = new DataView(buffer)
+ this.offset = 0
+}
+
+CBORDecode.prototype.empty = function() {
+ return this.offset >= this.buf.byteLength
+}
+
+CBORDecode.prototype.getU8 = function() {
+ let r = this.v.getUint8(this.offset)
+ this.offset += 1
+ return r
+}
+
+CBORDecode.prototype.getU16 = function() {
+ let r = this.v.getUint16(this.offset)
+ this.offset += 2
+ return r
+}
+
+CBORDecode.prototype.getU32 = function() {
+ let r = this.v.getUint32(this.offset)
+ this.offset += 4
+ return r
+}
+
+CBORDecode.prototype.getU64 = function() {
+ let r = this.v.getUint64(this.offset)
+ this.offset += 8
+ return r
+}
+
+CBORDecode.prototype.getCBORTypeLen = function() {
+ let tl, t, l
+ tl = this.getU8()
+ t = (tl & 0xe0) >> 5
+ l = tl & 0x1f
+ return [t, this.decodeInteger(l)]
+}
+
+CBORDecode.prototype.decodeInteger = function(len) {
+ switch (len) {
+ case 0x18: return this.getU8()
+ case 0x19: return this.getU16()
+ case 0x20: return this.getU32()
+ case 0x21: return this.getU64()
+ default:
+ if (len <= 23) {
+ return len
+ }
+ throw new Error("Unsupported int type 0x" + len.toString(16))
+ }
+}
+
+CBORDecode.prototype.decodeNegint = function(len) {
+ let r = -(this.decodeInteger(len) + 1)
+ return r
+}
+
+CBORDecode.prototype.decodeByteString = function(len) {
+ let r = this.buf.slice(this.offset, this.offset + len)
+ this.offset += len
+ return r
+}
+
+CBORDecode.prototype.decodeTextString = function(len) {
+ let u8dec = new TextDecoder('utf-8')
+ r = u8dec.decode(this.decodeByteString(len))
+ return r
+}
+
+CBORDecode.prototype.decodeArray = function(len, level) {
+ let r = []
+ for (let i = 0; i < len; i++) {
+ let v = this.decodeInternal(level)
+ r.push(v)
+ // console.log("decodeArray level " + level.toString() + " index " + i.toString() + " value " + JSON.stringify(v))
+ }
+ return r
+}
+
+CBORDecode.prototype.decodeMap = function(len, level) {
+ let r = {}
+ for (let i = 0; i < len; i++) {
+ let k = this.decodeInternal(level)
+ let v = this.decodeInternal(level)
+ r[k] = v
+ // console.log("decodeMap level " + level.toString() + " key " + k.toString() + " value " + JSON.stringify(v))
+ // XXX check string keys, duplicates
+ }
+ return r
+}
+
+CBORDecode.prototype.decodePrimitive = function(t) {
+ switch (t) {
+ case 20: return false
+ case 21: return true
+ case 22: return null
+ case 23: return undefined
+ default:
+ throw new Error("Unsupported primitive 0x" + t.toString(2))
+ }
+}
+
+CBORDecode.prototype.decodeInternal = function(level) {
+ if (level > 256) {
+ throw new Error("CBOR nesting too deep")
+ }
+ let t, l, r
+ [t, l] = this.getCBORTypeLen()
+ // console.log("decode level " + level.toString() + " type " + t.toString() + " len " + l.toString())
+ switch (t) {
+ case 0:
+ r = this.decodeInteger(l)
+ break
+ case 1:
+ r = this.decodeNegint(l)
+ break
+ case 2:
+ r = this.decodeByteString(l)
+ break
+ case 3:
+ r = this.decodeTextString(l)
+ break
+ case 4:
+ r = this.decodeArray(l, level + 1)
+ break
+ case 5:
+ r = this.decodeMap(l, level + 1)
+ break
+ case 6:
+ console.log("XXX ignored semantic tag " + this.decodeInteger(l).toString())
+ break;
+ case 7:
+ r = this.decodePrimitive(l)
+ break
+ default:
+ throw new Error("Unsupported type 0x" + t.toString(2) + " len " + l.toString())
+ }
+ // console.log("decode level " + level.toString() + " value " + JSON.stringify(r))
+ return r
+}
+
+CBORDecode.prototype.decode = function() {
+ return this.decodeInternal(0)
+}
+
+// ------------------------------------------------------------------
+// a crappy SSH message packer - 20200401 djm@openbsd.org
+
+var SSHMSG = function() {
+ this.r = []
+}
+
+SSHMSG.prototype.length = function() {
+ let len = 0
+ for (buf of this.r) {
+ len += buf.length
+ }
+ return len
+}
+
+SSHMSG.prototype.serialise = function() {
+ let r = new ArrayBuffer(this.length())
+ let v = new Uint8Array(r)
+ let offset = 0
+ for (buf of this.r) {
+ v.set(buf, offset)
+ offset += buf.length
+ }
+ if (offset != r.byteLength) {
+ throw new Error("djm can't count")
+ }
+ return r
+}
+
+SSHMSG.prototype.serialiseBase64 = function(v) {
+ let b = this.serialise()
+ return btoa(String.fromCharCode(...new Uint8Array(b)));
+}
+
+SSHMSG.prototype.putU8 = function(v) {
+ this.r.push(new Uint8Array([v]))
+}
+
+SSHMSG.prototype.putU32 = function(v) {
+ this.r.push(new Uint8Array([
+ (v >> 24) & 0xff,
+ (v >> 16) & 0xff,
+ (v >> 8) & 0xff,
+ (v & 0xff)
+ ]))
+}
+
+SSHMSG.prototype.put = function(v) {
+ this.r.push(new Uint8Array(v))
+}
+
+SSHMSG.prototype.putStringRaw = function(v) {
+ let enc = new TextEncoder();
+ let venc = enc.encode(v)
+ this.put(venc)
+}
+
+SSHMSG.prototype.putString = function(v) {
+ let enc = new TextEncoder();
+ let venc = enc.encode(v)
+ this.putU32(venc.length)
+ this.put(venc)
+}
+
+SSHMSG.prototype.putSSHMSG = function(v) {
+ let msg = v.serialise()
+ this.putU32(msg.byteLength)
+ this.put(msg)
+}
+
+SSHMSG.prototype.putBytes = function(v) {
+ this.putU32(v.byteLength)
+ this.put(v)
+}
+
+SSHMSG.prototype.putECPoint = function(x, y) {
+ let x8 = new Uint8Array(x)
+ let y8 = new Uint8Array(y)
+ this.putU32(1 + x8.length + y8.length)
+ this.putU8(0x04) // Uncompressed point format.
+ this.put(x8)
+ this.put(y8)
+}
+
+// ------------------------------------------------------------------
+// webauthn to SSH glue - djm@openbsd.org 20200408
+
+function error(msg, ...args) {
+ document.getElementById("error").innerText = msg
+ console.log(msg)
+ for (const arg of args) {
+ console.dir(arg)
+ }
+}
+function hexdump(buf) {
+ const hex = Array.from(new Uint8Array(buf)).map(
+ b => b.toString(16).padStart(2, "0"))
+ const fmt = new Array()
+ for (let i = 0; i < hex.length; i++) {
+ if ((i % 16) == 0) {
+ // Prepend length every 16 bytes.
+ fmt.push(i.toString(16).padStart(4, "0"))
+ fmt.push(" ")
+ }
+ fmt.push(hex[i])
+ fmt.push(" ")
+ if ((i % 16) == 15) {
+ fmt.push("\n")
+ }
+ }
+ return fmt.join("")
+}
+function enrollform_submit(event) {
+ event.preventDefault();
+ console.log("submitted")
+ username = event.target.elements.username.value
+ if (username === "") {
+ error("no username specified")
+ return false
+ }
+ enrollStart(username)
+}
+function enrollStart(username) {
+ let challenge = new Uint8Array(32)
+ window.crypto.getRandomValues(challenge)
+ let userid = new Uint8Array(8)
+ window.crypto.getRandomValues(userid)
+
+ console.log("challenge:" + btoa(challenge))
+ console.log("userid:" + btoa(userid))
+
+ let pkopts = {
+ challenge: challenge,
+ rp: {
+ name: "mindrot.org",
+ id: "mindrot.org",
+ },
+ user: {
+ id: userid,
+ name: username,
+ displayName: username,
+ },
+ authenticatorSelection: {
+ authenticatorAttachment: "cross-platform",
+ userVerification: "discouraged",
+ },
+ pubKeyCredParams: [{alg: -7, type: "public-key"}], // ES256
+ timeout: 30 * 1000,
+ };
+ console.dir(pkopts)
+ window.enrollOpts = pkopts
+ let credpromise = navigator.credentials.create({ publicKey: pkopts });
+ credpromise.then(enrollSuccess, enrollFailure)
+}
+function enrollFailure(result) {
+ error("Enroll failed", result)
+}
+function enrollSuccess(result) {
+ console.log("Enroll succeeded")
+ console.dir(result)
+ window.enrollResult = result
+ document.getElementById("enrollresult").style.visibility = "visible"
+
+ // Show the clientData
+ let u8dec = new TextDecoder('utf-8')
+ clientData = u8dec.decode(result.response.clientDataJSON)
+ document.getElementById("enrollresultjson").innerText = clientData
+
+ // Show the raw key handle.
+ document.getElementById("keyhandle").innerText = hexdump(result.rawId)
+
+ // Decode and show the attestationObject
+ document.getElementById("enrollresultraw").innerText = hexdump(result.response.attestationObject)
+ let aod = new CBORDecode(result.response.attestationObject)
+ let attestationObject = aod.decode()
+ console.log("attestationObject")
+ console.dir(attestationObject)
+ document.getElementById("enrollresultattestobj").innerText = JSON.stringify(attestationObject)
+
+ // Decode and show the authData
+ document.getElementById("enrollresultauthdataraw").innerText = hexdump(attestationObject.authData)
+ let authData = decodeAuthenticatorData(attestationObject.authData, true)
+ console.log("authData")
+ console.dir(authData)
+ window.enrollAuthData = authData
+ document.getElementById("enrollresultauthdata").innerText = JSON.stringify(authData)
+
+ // Reformat the pubkey as a SSH key for easy verification
+ window.rawKey = reformatPubkey(authData.attestedCredentialData.credentialPublicKey, window.enrollOpts.rp.id)
+ console.log("SSH pubkey blob")
+ console.dir(window.rawKey)
+ document.getElementById("enrollresultpkblob").innerText = hexdump(window.rawKey)
+ let pk64 = btoa(String.fromCharCode(...new Uint8Array(window.rawKey)));
+ let pk = "sk-ecdsa-sha2-nistp256@openssh.com " + pk64
+ document.getElementById("enrollresultpk").innerText = pk
+
+ // Format a private key too.
+ flags = 0x01 // SSH_SK_USER_PRESENCE_REQD
+ window.rawPrivkey = reformatPrivkey(authData.attestedCredentialData.credentialPublicKey, window.enrollOpts.rp.id, result.rawId, flags)
+ let privkeyFileBlob = privkeyFile(window.rawKey, window.rawPrivkey, window.enrollOpts.user.name, window.enrollOpts.rp.id)
+ let privk64 = btoa(String.fromCharCode(...new Uint8Array(privkeyFileBlob)));
+ let privkey = "-----BEGIN OPENSSH PRIVATE KEY-----\n" + wrapString(privk64, 70) + "-----END OPENSSH PRIVATE KEY-----\n"
+ document.getElementById("enrollresultprivkey").innerText = privkey
+
+ // Success: show the assertion form.
+ document.getElementById("assertsection").style.visibility = "visible"
+}
+
+function decodeAuthenticatorData(authData, expectCred) {
+ let r = new Object()
+ let v = new DataView(authData)
+
+ r.rpIdHash = authData.slice(0, 32)
+ r.flags = v.getUint8(32)
+ r.signCount = v.getUint32(33)
+
+ // Decode attestedCredentialData if present.
+ let offset = 37
+ let acd = new Object()
+ if (expectCred) {
+ acd.aaguid = authData.slice(offset, offset+16)
+ offset += 16
+ let credentialIdLength = v.getUint16(offset)
+ offset += 2
+ acd.credentialIdLength = credentialIdLength
+ acd.credentialId = authData.slice(offset, offset+credentialIdLength)
+ offset += credentialIdLength
+ r.attestedCredentialData = acd
+ }
+ console.log("XXXXX " + offset.toString())
+ let pubkeyrest = authData.slice(offset, authData.byteLength)
+ let pkdecode = new CBORDecode(pubkeyrest)
+ if (expectCred) {
+ // XXX unsafe: doesn't mandate COSE canonical format.
+ acd.credentialPublicKey = pkdecode.decode()
+ }
+ if (!pkdecode.empty()) {
+ // Decode extensions if present.
+ r.extensions = pkdecode.decode()
+ }
+ return r
+}
+
+function wrapString(s, l) {
+ ret = ""
+ for (i = 0; i < s.length; i += l) {
+ ret += s.slice(i, i + l) + "\n"
+ }
+ return ret
+}
+
+function checkPubkey(pk) {
+ // pk is in COSE format. We only care about a tiny subset.
+ if (pk[1] != 2) {
+ console.dir(pk)
+ throw new Error("pubkey is not EC")
+ }
+ if (pk[-1] != 1) {
+ throw new Error("pubkey is not in P256")
+ }
+ if (pk[3] != -7) {
+ throw new Error("pubkey is not ES256")
+ }
+ if (pk[-2].byteLength != 32 || pk[-3].byteLength != 32) {
+ throw new Error("pubkey EC coords have bad length")
+ }
+}
+
+function reformatPubkey(pk, rpid) {
+ checkPubkey(pk)
+ let msg = new SSHMSG()
+ msg.putString("sk-ecdsa-sha2-nistp256@openssh.com") // Key type
+ msg.putString("nistp256") // Key curve
+ msg.putECPoint(pk[-2], pk[-3]) // EC key
+ msg.putString(rpid) // RP ID
+ return msg.serialise()
+}
+
+function reformatPrivkey(pk, rpid, kh, flags) {
+ checkPubkey(pk)
+ let msg = new SSHMSG()
+ msg.putString("sk-ecdsa-sha2-nistp256@openssh.com") // Key type
+ msg.putString("nistp256") // Key curve
+ msg.putECPoint(pk[-2], pk[-3]) // EC key
+ msg.putString(rpid) // RP ID
+ msg.putU8(flags) // flags
+ msg.putBytes(kh) // handle
+ msg.putString("") // reserved
+ return msg.serialise()
+}
+
+function privkeyFile(pub, priv, user, rp) {
+ let innerMsg = new SSHMSG()
+ innerMsg.putU32(0xdeadbeef) // check byte
+ innerMsg.putU32(0xdeadbeef) // check byte
+ innerMsg.put(priv) // privkey
+ innerMsg.putString("webauthn.html " + user + "@" + rp) // comment
+ // Pad to cipher blocksize (8).
+ p = 1
+ while (innerMsg.length() % 8 != 0) {
+ innerMsg.putU8(p++)
+ }
+ let msg = new SSHMSG()
+ msg.putStringRaw("openssh-key-v1") // Magic
+ msg.putU8(0) // \0 terminate
+ msg.putString("none") // cipher
+ msg.putString("none") // KDF
+ msg.putString("") // KDF options
+ msg.putU32(1) // nkeys
+ msg.putBytes(pub) // pubkey
+ msg.putSSHMSG(innerMsg) // inner
+ //msg.put(innerMsg.serialise()) // inner
+ return msg.serialise()
+}
+
+async function assertform_submit(event) {
+ event.preventDefault();
+ console.log("submitted")
+ message = event.target.elements.message.value
+ if (message === "") {
+ error("no message specified")
+ return false
+ }
+ let enc = new TextEncoder()
+ let encmsg = enc.encode(message)
+ window.assertSignRaw = !event.target.elements.message_sshsig.checked
+ console.log("using sshsig ", !window.assertSignRaw)
+ if (window.assertSignRaw) {
+ assertStart(encmsg)
+ return
+ }
+ // Format a sshsig-style message.
+ window.sigHashAlg = "sha512"
+ let msghash = await crypto.subtle.digest("SHA-512", encmsg);
+ console.log("raw message hash")
+ console.dir(msghash)
+ window.sigNamespace = event.target.elements.message_namespace.value
+ let sigbuf = new SSHMSG()
+ sigbuf.put(enc.encode("SSHSIG"))
+ sigbuf.putString(window.sigNamespace)
+ sigbuf.putU32(0) // Reserved string
+ sigbuf.putString(window.sigHashAlg)
+ sigbuf.putBytes(msghash)
+ let msg = sigbuf.serialise()
+ console.log("sigbuf")
+ console.dir(msg)
+ assertStart(msg)
+}
+
+function assertStart(message) {
+ let assertReqOpts = {
+ challenge: message,
+ rpId: "mindrot.org",
+ allowCredentials: [{
+ type: 'public-key',
+ id: window.enrollResult.rawId,
+ }],
+ userVerification: "discouraged",
+ timeout: (30 * 1000),
+ }
+ console.log("assertReqOpts")
+ console.dir(assertReqOpts)
+ window.assertReqOpts = assertReqOpts
+ let assertpromise = navigator.credentials.get({
+ publicKey: assertReqOpts
+ });
+ assertpromise.then(assertSuccess, assertFailure)
+}
+function assertFailure(result) {
+ error("Assertion failed", result)
+}
+function linewrap(s) {
+ const linelen = 70
+ let ret = ""
+ for (let i = 0; i < s.length; i += linelen) {
+ end = i + linelen
+ if (end > s.length) {
+ end = s.length
+ }
+ if (i > 0) {
+ ret += "\n"
+ }
+ ret += s.slice(i, end)
+ }
+ return ret + "\n"
+}
+function assertSuccess(result) {
+ console.log("Assertion succeeded")
+ console.dir(result)
+ window.assertResult = result
+ document.getElementById("assertresult").style.visibility = "visible"
+
+ // show the clientData.
+ let u8dec = new TextDecoder('utf-8')
+ clientData = u8dec.decode(result.response.clientDataJSON)
+ document.getElementById("assertresultjson").innerText = clientData
+
+ // show the signature.
+ document.getElementById("assertresultsigraw").innerText = hexdump(result.response.signature)
+
+ // decode and show the authData.
+ document.getElementById("assertresultauthdataraw").innerText = hexdump(result.response.authenticatorData)
+ authData = decodeAuthenticatorData(result.response.authenticatorData, false)
+ document.getElementById("assertresultauthdata").innerText = JSON.stringify(authData)
+
+ // Parse and reformat the signature to an SSH style signature.
+ let sshsig = reformatSignature(result.response.signature, clientData, authData)
+ document.getElementById("assertresultsshsigraw").innerText = hexdump(sshsig)
+ let sig64 = btoa(String.fromCharCode(...new Uint8Array(sshsig)));
+ if (window.assertSignRaw) {
+ document.getElementById("assertresultsshsigb64").innerText = sig64
+ } else {
+ document.getElementById("assertresultsshsigb64").innerText =
+ "-----BEGIN SSH SIGNATURE-----\n" + linewrap(sig64) +
+ "-----END SSH SIGNATURE-----\n";
+ }
+}
+
+function reformatSignature(sig, clientData, authData) {
+ if (sig.byteLength < 2) {
+ throw new Error("signature is too short")
+ }
+ let offset = 0
+ let v = new DataView(sig)
+ // Expect an ASN.1 SEQUENCE that exactly spans the signature.
+ if (v.getUint8(offset) != 0x30) {
+ throw new Error("signature not an ASN.1 sequence")
+ }
+ offset++
+ let seqlen = v.getUint8(offset)
+ offset++
+ if ((seqlen & 0x80) != 0 || seqlen != sig.byteLength - offset) {
+ throw new Error("signature has unexpected length " + seqlen.toString() + " vs expected " + (sig.byteLength - offset).toString())
+ }
+
+ // Parse 'r' INTEGER value.
+ if (v.getUint8(offset) != 0x02) {
+ throw new Error("signature r not an ASN.1 integer")
+ }
+ offset++
+ let rlen = v.getUint8(offset)
+ offset++
+ if ((rlen & 0x80) != 0 || rlen > sig.byteLength - offset) {
+ throw new Error("signature r has unexpected length " + rlen.toString() + " vs buffer " + (sig.byteLength - offset).toString())
+ }
+ let r = sig.slice(offset, offset + rlen)
+ offset += rlen
+ console.log("sig_r")
+ console.dir(r)
+
+ // Parse 's' INTEGER value.
+ if (v.getUint8(offset) != 0x02) {
+ throw new Error("signature r not an ASN.1 integer")
+ }
+ offset++
+ let slen = v.getUint8(offset)
+ offset++
+ if ((slen & 0x80) != 0 || slen > sig.byteLength - offset) {
+ throw new Error("signature s has unexpected length " + slen.toString() + " vs buffer " + (sig.byteLength - offset).toString())
+ }
+ let s = sig.slice(offset, offset + slen)
+ console.log("sig_s")
+ console.dir(s)
+ offset += slen
+
+ if (offset != sig.byteLength) {
+ throw new Error("unexpected final offset during signature parsing " + offset.toString() + " expected " + sig.byteLength.toString())
+ }
+
+ // Reformat as an SSH signature.
+ let clientDataParsed = JSON.parse(clientData)
+ let innersig = new SSHMSG()
+ innersig.putBytes(r)
+ innersig.putBytes(s)
+
+ let rawsshsig = new SSHMSG()
+ rawsshsig.putString("webauthn-sk-ecdsa-sha2-nistp256@openssh.com")
+ rawsshsig.putSSHMSG(innersig)
+ rawsshsig.putU8(authData.flags)
+ rawsshsig.putU32(authData.signCount)
+ rawsshsig.putString(clientDataParsed.origin)
+ rawsshsig.putString(clientData)
+ if (authData.extensions == undefined) {
+ rawsshsig.putU32(0)
+ } else {
+ rawsshsig.putBytes(authData.extensions)
+ }
+
+ if (window.assertSignRaw) {
+ return rawsshsig.serialise()
+ }
+ // Format as SSHSIG.
+ let enc = new TextEncoder()
+ let sshsig = new SSHMSG()
+ sshsig.put(enc.encode("SSHSIG"))
+ sshsig.putU32(0x01) // Signature version.
+ sshsig.putBytes(window.rawKey)
+ sshsig.putString(window.sigNamespace)
+ sshsig.putU32(0) // Reserved string
+ sshsig.putString(window.sigHashAlg)
+ sshsig.putBytes(rawsshsig.serialise())
+ return sshsig.serialise()
+}
+
+function toggleNamespaceVisibility() {
+ const assertsigtype = document.getElementById('message_sshsig');
+ const assertsignamespace = document.getElementById('message_namespace');
+ assertsignamespace.disabled = !assertsigtype.checked;
+}
+
+function init() {
+ if (document.location.protocol != "https:") {
+ error("This page must be loaded via https")
+ const assertsubmit = document.getElementById('assertsubmit')
+ assertsubmit.disabled = true
+ }
+ const enrollform = document.getElementById('enrollform');
+ enrollform.addEventListener('submit', enrollform_submit);
+ const assertform = document.getElementById('assertform');
+ assertform.addEventListener('submit', assertform_submit);
+ const assertsigtype = document.getElementById('message_sshsig');
+ assertsigtype.onclick = toggleNamespaceVisibility;
+}
+</script>
+
+</html>
diff --git a/regress/valgrind-unit.sh b/regress/valgrind-unit.sh
index 4143ead4b..193289e6b 100755
--- a/regress/valgrind-unit.sh
+++ b/regress/valgrind-unit.sh
@@ -19,4 +19,6 @@ if [ "x$VALGRIND_PATH" != "x" ]; then
VG_PATH="$VALGRIND_PATH"
fi
+mkdir -p "$OBJ/valgrind-out"
+
exec $VG_PATH $VG_OPTS $UNIT_BINARY $UNIT_ARGS