summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
Diffstat (limited to 'regress')
-rw-r--r--regress/Makefile5
-rw-r--r--regress/addrmatch.sh14
-rw-r--r--regress/agent-subprocess.sh22
-rw-r--r--regress/agent.sh73
-rw-r--r--regress/misc/sk-dummy/sk-dummy.c2
-rw-r--r--regress/multiplex.sh14
-rw-r--r--regress/netcat.c38
-rw-r--r--regress/percent.sh51
-rw-r--r--regress/servcfginclude.sh36
-rw-r--r--regress/unittests/Makefile4
-rw-r--r--regress/unittests/match/tests.c4
-rw-r--r--regress/unittests/misc/tests.c88
-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.html692
64 files changed, 1637 insertions, 58 deletions
diff --git a/regress/Makefile b/regress/Makefile
index 53a50ffca..f50d189bb 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.108 2020/04/20 04:44:47 djm Exp $ 1# $OpenBSD: Makefile,v 1.109 2020/06/19 05:07:09 dtucker Exp $
2 2
3tests: prep file-tests t-exec unit 3tests: prep file-tests t-exec unit
4 4
@@ -41,6 +41,7 @@ LTESTS= connect \
41 agent-getpeereid \ 41 agent-getpeereid \
42 agent-timeout \ 42 agent-timeout \
43 agent-ptrace \ 43 agent-ptrace \
44 agent-subprocess \
44 keyscan \ 45 keyscan \
45 keygen-change \ 46 keygen-change \
46 keygen-convert \ 47 keygen-convert \
@@ -250,6 +251,8 @@ unit:
250 $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ 251 $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
251 $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ 252 $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
252 -d ${.CURDIR}/unittests/sshkey/testdata ; \ 253 -d ${.CURDIR}/unittests/sshkey/testdata ; \
254 $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \
255 -d ${.CURDIR}/unittests/sshsig/testdata ; \
253 $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ 256 $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \
254 $$V ${.OBJDIR}/unittests/conversion/test_conversion ; \ 257 $$V ${.OBJDIR}/unittests/conversion/test_conversion ; \
255 $$V ${.OBJDIR}/unittests/kex/test_kex ; \ 258 $$V ${.OBJDIR}/unittests/kex/test_kex ; \
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 @@
1# $OpenBSD: addrmatch.sh,v 1.5 2020/03/13 03:18:45 djm Exp $ 1# $OpenBSD: addrmatch.sh,v 1.6 2020/08/28 03:17:13 dtucker Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="address match" 4tid="address match"
@@ -52,5 +52,17 @@ run_trial user ::5 somehost ::1 1234 match3 "IP6 localaddress"
52run_trial user ::5 somehost ::2 5678 match4 "IP6 localport" 52run_trial user ::5 somehost ::2 5678 match4 "IP6 localport"
53fi 53fi
54 54
55#
56# Check that we catch invalid address/mask in Match Address/Localaddress
57#
58for i in 10.0.1.0/8 10.0.0.1/24 2000:aa:bb:01::/56; do
59 for a in address localaddress; do
60 verbose "test invalid Match $a $i"
61 echo "Match $a $i" > $OBJ/sshd_proxy
62 ${SUDO} ${SSHD} -f $OBJ/sshd_proxy -t >/dev/null 2>&1 && \
63 fail "accepted invalid match $a $i"
64 done
65done
66
55cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy 67cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
56rm $OBJ/sshd_proxy_bak 68rm $OBJ/sshd_proxy_bak
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 @@
1# $OpenBSD: agent-subprocess.sh,v 1.1 2020/06/19 05:07:09 dtucker Exp $
2# Placed in the Public Domain.
3
4tid="agent subprocess"
5
6trace "ensure agent exits when run as subprocess"
7${SSHAGENT} sh -c "echo \$SSH_AGENT_PID >$OBJ/pidfile; sleep 1"
8
9pid=`cat $OBJ/pidfile`
10
11# Currently ssh-agent polls every 10s so we need to wait at least that long.
12n=12
13while kill -0 $pid >/dev/null 2>&1 && test "$n" -gt "0"; do
14 n=$(($n - 1))
15 sleep 1
16done
17
18if test "$n" -eq "0"; then
19 fail "agent still running"
20fi
21
22rm -f $OBJ/pidfile
diff --git a/regress/agent.sh b/regress/agent.sh
index 39403653c..a3ad1385f 100644
--- a/regress/agent.sh
+++ b/regress/agent.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: agent.sh,v 1.17 2019/12/21 02:33:07 djm Exp $ 1# $OpenBSD: agent.sh,v 1.19 2020/07/15 04:55:47 dtucker Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="simple agent test" 4tid="simple agent test"
@@ -45,17 +45,20 @@ for t in ${SSH_KEYTYPES}; do
45 # add to authorized keys 45 # add to authorized keys
46 cat $OBJ/$t-agent.pub >> $OBJ/authorized_keys_$USER 46 cat $OBJ/$t-agent.pub >> $OBJ/authorized_keys_$USER
47 # add private key to agent 47 # add private key to agent
48 ${SSHADD} $OBJ/$t-agent #> /dev/null 2>&1 48 ${SSHADD} $OBJ/$t-agent > /dev/null 2>&1
49 if [ $? -ne 0 ]; then 49 if [ $? -ne 0 ]; then
50 fail "ssh-add failed exit code $?" 50 fail "ssh-add failed exit code $?"
51 fi 51 fi
52 # add private key to second agent 52 # add private key to second agent
53 SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} $OBJ/$t-agent #> /dev/null 2>&1 53 SSH_AUTH_SOCK=$FW_SSH_AUTH_SOCK ${SSHADD} $OBJ/$t-agent > /dev/null 2>&1
54 if [ $? -ne 0 ]; then 54 if [ $? -ne 0 ]; then
55 fail "ssh-add failed exit code $?" 55 fail "ssh-add failed exit code $?"
56 fi 56 fi
57 # Remove private key to ensure that we aren't accidentally using it. 57 # Move private key to ensure that we aren't accidentally using it.
58 rm -f $OBJ/$t-agent 58 # Keep the corresponding public keys/certs around for later use.
59 mv -f $OBJ/$t-agent $OBJ/$t-agent-private
60 cp -f $OBJ/$t-agent.pub $OBJ/$t-agent-private.pub
61 cp -f $OBJ/$t-agent-cert.pub $OBJ/$t-agent-private-cert.pub
59done 62done
60 63
61# Remove explicit identity directives from ssh_proxy 64# Remove explicit identity directives from ssh_proxy
@@ -152,12 +155,72 @@ for t in ${SSH_KEYTYPES}; do
152 fi 155 fi
153done 156done
154 157
158## Deletion tests.
159
155trace "delete all agent keys" 160trace "delete all agent keys"
156${SSHADD} -D > /dev/null 2>&1 161${SSHADD} -D > /dev/null 2>&1
157r=$? 162r=$?
158if [ $r -ne 0 ]; then 163if [ $r -ne 0 ]; then
159 fail "ssh-add -D failed: exit code $r" 164 fail "ssh-add -D failed: exit code $r"
160fi 165fi
166# make sure they're gone
167${SSHADD} -l > /dev/null 2>&1
168r=$?
169if [ $r -ne 1 ]; then
170 fail "ssh-add -l returned unexpected exit code: $r"
171fi
172trace "readd keys"
173# re-add keys/certs to agent
174for t in ${SSH_KEYTYPES}; do
175 ${SSHADD} $OBJ/$t-agent-private >/dev/null 2>&1 || \
176 fail "ssh-add failed exit code $?"
177done
178# make sure they are there
179${SSHADD} -l > /dev/null 2>&1
180r=$?
181if [ $r -ne 0 ]; then
182 fail "ssh-add -l failed: exit code $r"
183fi
184
185check_key_absent() {
186 ${SSHADD} -L | grep "^$1 " >/dev/null
187 if [ $? -eq 0 ]; then
188 fail "$1 key unexpectedly present"
189 fi
190}
191check_key_present() {
192 ${SSHADD} -L | grep "^$1 " >/dev/null
193 if [ $? -ne 0 ]; then
194 fail "$1 key missing from agent"
195 fi
196}
197
198# delete the ed25519 key
199trace "delete single key by file"
200${SSHADD} -qdk $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed"
201check_key_absent ssh-ed25519
202check_key_present ssh-ed25519-cert-v01@openssh.com
203# Put key/cert back.
204${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \
205 fail "ssh-add failed exit code $?"
206check_key_present ssh-ed25519
207# Delete both key and certificate.
208trace "delete key/cert by file"
209${SSHADD} -qd $OBJ/ssh-ed25519-agent || fail "ssh-add -d ed25519 failed"
210check_key_absent ssh-ed25519
211check_key_absent ssh-ed25519-cert-v01@openssh.com
212# Put key/cert back.
213${SSHADD} $OBJ/ssh-ed25519-agent-private >/dev/null 2>&1 || \
214 fail "ssh-add failed exit code $?"
215check_key_present ssh-ed25519
216# Delete certificate via stdin
217${SSHADD} -qd - < $OBJ/ssh-ed25519-agent-cert.pub || fail "ssh-add -d - failed"
218check_key_present ssh-ed25519
219check_key_absent ssh-ed25519-cert-v01@openssh.com
220# Delete key via stdin
221${SSHADD} -qd - < $OBJ/ssh-ed25519-agent.pub || fail "ssh-add -d - failed"
222check_key_absent ssh-ed25519
223check_key_absent ssh-ed25519-cert-v01@openssh.com
161 224
162trace "kill agent" 225trace "kill agent"
163${SSHAGENT} -k > /dev/null 226${SSHAGENT} -k > /dev/null
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c
index f3acb2fb7..bf1feec15 100644
--- a/regress/misc/sk-dummy/sk-dummy.c
+++ b/regress/misc/sk-dummy/sk-dummy.c
@@ -47,7 +47,7 @@
47 } while (0) 47 } while (0)
48#endif 48#endif
49 49
50#if SSH_SK_VERSION_MAJOR != 0x00050000 50#if SSH_SK_VERSION_MAJOR != 0x00070000
51# error SK API has changed, sk-dummy.c needs an update 51# error SK API has changed, sk-dummy.c needs an update
52#endif 52#endif
53 53
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 @@
1# $OpenBSD: multiplex.sh,v 1.32 2020/01/25 02:57:53 dtucker Exp $ 1# $OpenBSD: multiplex.sh,v 1.33 2020/06/24 15:16:23 markus Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4make_tmpdir 4make_tmpdir
@@ -97,22 +97,24 @@ kill $netcat_pid 2>/dev/null
97rm -f ${COPY} $OBJ/unix-[123].fwd 97rm -f ${COPY} $OBJ/unix-[123].fwd
98 98
99for s in 0 1 4 5 44; do 99for s in 0 1 4 5 44; do
100 trace "exit status $s over multiplexed connection" 100 for mode in "" "-Oproxy"; do
101 verbose "test $tid: status $s" 101 trace "exit status $s over multiplexed connection ($mode)"
102 ${SSH} -F $OBJ/ssh_config -S $CTL otherhost exit $s 102 verbose "test $tid: status $s ($mode)"
103 ${SSH} -F $OBJ/ssh_config -S $CTL $mode otherhost exit $s
103 r=$? 104 r=$?
104 if [ $r -ne $s ]; then 105 if [ $r -ne $s ]; then
105 fail "exit code mismatch: $r != $s" 106 fail "exit code mismatch: $r != $s"
106 fi 107 fi
107 108
108 # same with early close of stdout/err 109 # same with early close of stdout/err
109 trace "exit status $s with early close over multiplexed connection" 110 trace "exit status $s with early close over multiplexed connection ($mode)"
110 ${SSH} -F $OBJ/ssh_config -S $CTL -n otherhost \ 111 ${SSH} -F $OBJ/ssh_config -S $CTL -n $mode otherhost \
111 exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\' 112 exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\'
112 r=$? 113 r=$?
113 if [ $r -ne $s ]; then 114 if [ $r -ne $s ]; then
114 fail "exit code (with sleep) mismatch: $r != $s" 115 fail "exit code (with sleep) mismatch: $r != $s"
115 fi 116 fi
117 done
116done 118done
117 119
118verbose "test $tid: cmd check" 120verbose "test $tid: cmd check"
diff --git a/regress/netcat.c b/regress/netcat.c
index fe94dd908..d583176f1 100644
--- a/regress/netcat.c
+++ b/regress/netcat.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: netcat.c,v 1.126 2014/10/30 16:08:31 tedu Exp $ */ 1/* $OpenBSD: netcat.c,v 1.131 2015/09/03 23:06:28 sobrado Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org> 3 * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
4 * 4 *
@@ -44,14 +44,15 @@
44#include <netinet/ip.h> 44#include <netinet/ip.h>
45 45
46#include <errno.h> 46#include <errno.h>
47#include <fcntl.h>
48#include <limits.h>
47#include <netdb.h> 49#include <netdb.h>
50#include <signal.h>
48#include <stdarg.h> 51#include <stdarg.h>
49#include <stdio.h> 52#include <stdio.h>
50#include <stdlib.h> 53#include <stdlib.h>
51#include <string.h> 54#include <string.h>
52#include <unistd.h> 55#include <unistd.h>
53#include <fcntl.h>
54#include <limits.h>
55#include "atomicio.h" 56#include "atomicio.h"
56 57
57#ifdef HAVE_POLL_H 58#ifdef HAVE_POLL_H
@@ -133,7 +134,7 @@ int udptest(int);
133int unix_bind(char *); 134int unix_bind(char *);
134int unix_connect(char *); 135int unix_connect(char *);
135int unix_listen(char *); 136int unix_listen(char *);
136void set_common_sockopts(int); 137void set_common_sockopts(int, int);
137int map_tos(char *, int *); 138int map_tos(char *, int *);
138void report_connect(const struct sockaddr *, socklen_t); 139void report_connect(const struct sockaddr *, socklen_t);
139void usage(int); 140void usage(int);
@@ -162,6 +163,8 @@ main(int argc, char *argv[])
162 uport = NULL; 163 uport = NULL;
163 sv = NULL; 164 sv = NULL;
164 165
166 signal(SIGPIPE, SIG_IGN);
167
165 while ((ch = getopt(argc, argv, 168 while ((ch = getopt(argc, argv,
166 "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) { 169 "46DdFhI:i:klNnO:P:p:rSs:tT:UuV:vw:X:x:z")) != -1) {
167 switch (ch) { 170 switch (ch) {
@@ -648,7 +651,7 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
648 freeaddrinfo(ares); 651 freeaddrinfo(ares);
649 } 652 }
650 653
651 set_common_sockopts(s); 654 set_common_sockopts(s, res0->ai_family);
652 655
653 if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0) 656 if (timeout_connect(s, res0->ai_addr, res0->ai_addrlen) == 0)
654 break; 657 break;
@@ -748,7 +751,7 @@ local_listen(char *host, char *port, struct addrinfo hints)
748 if (ret == -1) 751 if (ret == -1)
749 err(1, "setsockopt SO_REUSEADDR"); 752 err(1, "setsockopt SO_REUSEADDR");
750#endif 753#endif
751 set_common_sockopts(s); 754 set_common_sockopts(s, res0->ai_family);
752 755
753 if (bind(s, (struct sockaddr *)res0->ai_addr, 756 if (bind(s, (struct sockaddr *)res0->ai_addr,
754 res0->ai_addrlen) == 0) 757 res0->ai_addrlen) == 0)
@@ -1034,17 +1037,17 @@ fdpass(int nfd)
1034 1037
1035 bzero(&pfd, sizeof(pfd)); 1038 bzero(&pfd, sizeof(pfd));
1036 pfd.fd = STDOUT_FILENO; 1039 pfd.fd = STDOUT_FILENO;
1040 pfd.events = POLLOUT;
1037 for (;;) { 1041 for (;;) {
1038 r = sendmsg(STDOUT_FILENO, &msg, 0); 1042 r = sendmsg(STDOUT_FILENO, &msg, 0);
1039 if (r == -1) { 1043 if (r == -1) {
1040 if (errno == EAGAIN || errno == EINTR) { 1044 if (errno == EAGAIN || errno == EINTR) {
1041 pfd.events = POLLOUT;
1042 if (poll(&pfd, 1, -1) == -1) 1045 if (poll(&pfd, 1, -1) == -1)
1043 err(1, "poll"); 1046 err(1, "poll");
1044 continue; 1047 continue;
1045 } 1048 }
1046 err(1, "sendmsg"); 1049 err(1, "sendmsg");
1047 } else if (r == -1) 1050 } else if (r != 1)
1048 errx(1, "sendmsg: unexpected return value %zd", r); 1051 errx(1, "sendmsg: unexpected return value %zd", r);
1049 else 1052 else
1050 break; 1053 break;
@@ -1168,7 +1171,7 @@ udptest(int s)
1168} 1171}
1169 1172
1170void 1173void
1171set_common_sockopts(int s) 1174set_common_sockopts(int s, int af)
1172{ 1175{
1173 int x = 1; 1176 int x = 1;
1174 1177
@@ -1184,10 +1187,19 @@ set_common_sockopts(int s)
1184 &x, sizeof(x)) == -1) 1187 &x, sizeof(x)) == -1)
1185 err(1, "setsockopt"); 1188 err(1, "setsockopt");
1186 } 1189 }
1187#ifdef IP_TOS 1190#if defined(IP_TOS) && defined(IPV6_TCLASS)
1188 if (Tflag != -1) { 1191 if (Tflag != -1) {
1189 if (setsockopt(s, IPPROTO_IP, IP_TOS, 1192 int proto, option;
1190 &Tflag, sizeof(Tflag)) == -1) 1193
1194 if (af == AF_INET6) {
1195 proto = IPPROTO_IPV6;
1196 option = IPV6_TCLASS;
1197 } else {
1198 proto = IPPROTO_IP;
1199 option = IP_TOS;
1200 }
1201
1202 if (setsockopt(s, proto, option, &Tflag, sizeof(Tflag)) == -1)
1191 err(1, "set IP ToS"); 1203 err(1, "set IP ToS");
1192 } 1204 }
1193#endif 1205#endif
@@ -1321,7 +1333,7 @@ usage(int ret)
1321{ 1333{
1322 fprintf(stderr, 1334 fprintf(stderr,
1323 "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n" 1335 "usage: nc [-46DdFhklNnrStUuvz] [-I length] [-i interval] [-O length]\n"
1324 "\t [-P proxy_username] [-p source_port] [-s source] [-T ToS]\n" 1336 "\t [-P proxy_username] [-p source_port] [-s source] [-T toskeyword]\n"
1325 "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n" 1337 "\t [-V rtable] [-w timeout] [-X proxy_protocol]\n"
1326 "\t [-x proxy_address[:port]] [destination] [port]\n"); 1338 "\t [-x proxy_address[:port]] [destination] [port]\n");
1327 if (ret) 1339 if (ret)
diff --git a/regress/percent.sh b/regress/percent.sh
index 2e891f693..28781117e 100644
--- a/regress/percent.sh
+++ b/regress/percent.sh
@@ -1,4 +1,4 @@
1# $OpenBSD: percent.sh,v 1.6 2020/04/10 00:54:03 dtucker Exp $ 1# $OpenBSD: percent.sh,v 1.9 2020/07/17 07:10:24 dtucker Exp $
2# Placed in the Public Domain. 2# Placed in the Public Domain.
3 3
4tid="percent expansions" 4tid="percent expansions"
@@ -25,12 +25,21 @@ trial()
25 25
26 trace "test $opt=$arg $expect" 26 trace "test $opt=$arg $expect"
27 rm -f $OBJ/actual 27 rm -f $OBJ/actual
28 got=""
28 case "$opt" in 29 case "$opt" in
29 localcommand) 30 localcommand)
30 ${SSH} -F $OBJ/ssh_proxy -o $opt="echo '$arg' >$OBJ/actual" \ 31 ${SSH} -F $OBJ/ssh_proxy -o $opt="echo '$arg' >$OBJ/actual" \
31 somehost true 32 somehost true
32 got=`cat $OBJ/actual` 33 got=`cat $OBJ/actual`
33 ;; 34 ;;
35 userknownhostsfile)
36 # Move the userknownhosts file to what the expansion says,
37 # make sure ssh works then put it back.
38 mv "$OBJ/known_hosts" "$OBJ/$expect"
39 ${SSH} -F $OBJ/ssh_proxy -o $opt="$OBJ/$arg" somehost true && \
40 got="$expect"
41 mv "$OBJ/$expect" "$OBJ/known_hosts"
42 ;;
34 matchexec) 43 matchexec)
35 (cat $OBJ/ssh_proxy && \ 44 (cat $OBJ/ssh_proxy && \
36 echo "Match Exec \"echo '$arg' >$OBJ/actual\"") \ 45 echo "Match Exec \"echo '$arg' >$OBJ/actual\"") \
@@ -55,13 +64,18 @@ trial()
55} 64}
56 65
57for i in matchexec localcommand remotecommand controlpath identityagent \ 66for i in matchexec localcommand remotecommand controlpath identityagent \
58 forwardagent localforward remoteforward; do 67 forwardagent localforward remoteforward userknownhostsfile; do
59 verbose $tid $i 68 verbose $tid $i percent
60 if [ "$i" = "localcommand" ]; then 69 case "$i" in
61 REMUSER=$USER 70 localcommand|userknownhostsfile)
71 # Any test that's going to actually make a connection needs
72 # to use the real username.
73 REMUSER=$USER ;;
74 *)
75 REMUSER=remuser ;;
76 esac
77 if [ "$i" = "$localcommand" ]; then
62 trial $i '%T' NONE 78 trial $i '%T' NONE
63 else
64 REMUSER=remuser
65 fi 79 fi
66 # Matches implementation in readconf.c:ssh_connection_hash() 80 # Matches implementation in readconf.c:ssh_connection_hash()
67 HASH=`printf "${HOSTNAME}127.0.0.1${PORT}$REMUSER" | 81 HASH=`printf "${HOSTNAME}127.0.0.1${PORT}$REMUSER" |
@@ -70,19 +84,36 @@ for i in matchexec localcommand remotecommand controlpath identityagent \
70 trial $i '%C' $HASH 84 trial $i '%C' $HASH
71 trial $i '%i' $USERID 85 trial $i '%i' $USERID
72 trial $i '%h' 127.0.0.1 86 trial $i '%h' 127.0.0.1
73 trial $i '%d' $HOME
74 trial $i '%L' $HOST 87 trial $i '%L' $HOST
75 trial $i '%l' $HOSTNAME 88 trial $i '%l' $HOSTNAME
76 trial $i '%n' somehost 89 trial $i '%n' somehost
90 trial $i '%k' localhost-with-alias
77 trial $i '%p' $PORT 91 trial $i '%p' $PORT
78 trial $i '%r' $REMUSER 92 trial $i '%r' $REMUSER
79 trial $i '%u' $USER 93 trial $i '%u' $USER
80 trial $i '%%/%C/%i/%h/%d/%L/%l/%n/%p/%r/%u' \ 94 # We can't specify a full path outside the regress dir, so skip tests
81 "%/$HASH/$USERID/127.0.0.1/$HOME/$HOST/$HOSTNAME/somehost/$PORT/$REMUSER/$USER" 95 # containing %d for UserKnownHostsFile
96 if [ "$i" != "userknownhostsfile" ]; then
97 trial $i '%d' $HOME
98 trial $i '%%/%C/%i/%h/%d/%L/%l/%n/%p/%r/%u' \
99 "%/$HASH/$USERID/127.0.0.1/$HOME/$HOST/$HOSTNAME/somehost/$PORT/$REMUSER/$USER"
100 fi
82done 101done
83 102
103# Subset of above since we don't expand shell-style variables on anything that
104# runs a command because the shell will expand those.
105for i in controlpath identityagent forwardagent localforward remoteforward \
106 userknownhostsfile; do
107 verbose $tid $i dollar
108 FOO=bar
109 export FOO
110 trial $i '${FOO}' $FOO
111done
112
113
84# A subset of options support tilde expansion 114# A subset of options support tilde expansion
85for i in controlpath identityagent forwardagent; do 115for i in controlpath identityagent forwardagent; do
116 verbose $tid $i tilde
86 trial $i '~' $HOME/ 117 trial $i '~' $HOME/
87 trial $i '~/.ssh' $HOME/.ssh 118 trial $i '~/.ssh' $HOME/.ssh
88done 119done
diff --git a/regress/servcfginclude.sh b/regress/servcfginclude.sh
index b25c8faa8..b6a9a248f 100644
--- a/regress/servcfginclude.sh
+++ b/regress/servcfginclude.sh
@@ -146,9 +146,43 @@ Include
146_EOF 146_EOF
147 147
148trace "disallow invalid with no argument" 148trace "disallow invalid with no argument"
149${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i.x \ 149${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i.x -T \
150 -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \ 150 -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
151 fail "sshd allowed Include with no argument" 151 fail "sshd allowed Include with no argument"
152 152
153# Ensure the Include before any Match block works as expected (bug #3122)
154cat > $OBJ/sshd_config.i << _EOF
155Banner /xx
156HostKey $OBJ/host.ssh-ed25519
157Include $OBJ/sshd_config.i.2
158Match host a
159 Banner /aaaa
160_EOF
161cat > $OBJ/sshd_config.i.2 << _EOF
162Match host a
163 Banner /aa
164_EOF
165
166trace "Include before match blocks"
167trial a /aa "included file before match blocks is properly evaluated"
168
169# Port in included file is correctly interpretted (bug #3169)
170cat > $OBJ/sshd_config.i << _EOF
171Include $OBJ/sshd_config.i.2
172Port 7722
173_EOF
174cat > $OBJ/sshd_config.i.2 << _EOF
175HostKey $OBJ/host.ssh-ed25519
176_EOF
177
178trace "Port after included files"
179${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i -T \
180 -C "host=x,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out || \
181 fail "failed to parse Port after included files"
182_port=`grep -i '^port ' $OBJ/sshd_config.out | awk '{print $2}'`
183if test "x7722" != "x$_port" ; then
184 fail "The Port in included file was intertepretted wrongly. Expected 7722, got $_port"
185fi
186
153# cleanup 187# cleanup
154rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out 188rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out
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 @@
1# $OpenBSD: Makefile,v 1.11 2019/04/28 22:53:26 dtucker Exp $ 1# $OpenBSD: Makefile,v 1.12 2020/06/19 04:34:21 djm Exp $
2 2
3REGRESS_FAIL_EARLY?= yes 3REGRESS_FAIL_EARLY?= yes
4SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion 4SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion
5SUBDIR+=authopt misc 5SUBDIR+=authopt misc sshsig
6 6
7.include <bsd.subdir.mk> 7.include <bsd.subdir.mk>
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 @@
1/* $OpenBSD: tests.c,v 1.5 2018/07/04 13:51:45 djm Exp $ */ 1/* $OpenBSD: tests.c,v 1.7 2020/07/15 06:43:16 dtucker Exp $ */
2/* 2/*
3 * Regress test for matching functions 3 * Regress test for matching functions
4 * 4 *
@@ -105,7 +105,7 @@ tests(void)
105 105
106#define CHECK_FILTER(string,filter,expected) \ 106#define CHECK_FILTER(string,filter,expected) \
107 do { \ 107 do { \
108 char *result = match_filter_blacklist((string), (filter)); \ 108 char *result = match_filter_denylist((string), (filter)); \
109 ASSERT_STRING_EQ(result, expected); \ 109 ASSERT_STRING_EQ(result, expected); \
110 free(result); \ 110 free(result); \
111 } while (0) 111 } while (0)
diff --git a/regress/unittests/misc/tests.c b/regress/unittests/misc/tests.c
index ed775ebbd..0bd0c84f9 100644
--- a/regress/unittests/misc/tests.c
+++ b/regress/unittests/misc/tests.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tests.c,v 1.1 2019/04/28 22:53:26 dtucker Exp $ */ 1/* $OpenBSD: tests.c,v 1.3 2020/05/29 04:32:26 dtucker Exp $ */
2/* 2/*
3 * Regress test for misc helper functions. 3 * Regress test for misc helper functions.
4 * 4 *
@@ -14,13 +14,14 @@
14 14
15#include "test_helper.h" 15#include "test_helper.h"
16 16
17#include "log.h"
17#include "misc.h" 18#include "misc.h"
18 19
19void 20void
20tests(void) 21tests(void)
21{ 22{
22 int port; 23 int port, parseerr;
23 char *user, *host, *path; 24 char *user, *host, *path, *ret;
24 25
25 TEST_START("misc_parse_user_host_path"); 26 TEST_START("misc_parse_user_host_path");
26 ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path", 27 ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path",
@@ -76,4 +77,85 @@ tests(void)
76 ASSERT_STRING_EQ(path, "some/path"); 77 ASSERT_STRING_EQ(path, "some/path");
77 free(user); free(host); free(path); 78 free(user); free(host); free(path);
78 TEST_DONE(); 79 TEST_DONE();
80
81 TEST_START("misc_convtime");
82 ASSERT_LONG_EQ(convtime("1"), 1);
83 ASSERT_LONG_EQ(convtime("2s"), 2);
84 ASSERT_LONG_EQ(convtime("3m"), 180);
85 ASSERT_LONG_EQ(convtime("1m30"), 90);
86 ASSERT_LONG_EQ(convtime("1m30s"), 90);
87 ASSERT_LONG_EQ(convtime("1h1s"), 3601);
88 ASSERT_LONG_EQ(convtime("1h30m"), 90 * 60);
89 ASSERT_LONG_EQ(convtime("1d"), 24 * 60 * 60);
90 ASSERT_LONG_EQ(convtime("1w"), 7 * 24 * 60 * 60);
91 ASSERT_LONG_EQ(convtime("1w2d3h4m5"), 788645);
92 ASSERT_LONG_EQ(convtime("1w2d3h4m5s"), 788645);
93 /* any negative number or error returns -1 */
94 ASSERT_LONG_EQ(convtime("-1"), -1);
95 ASSERT_LONG_EQ(convtime(""), -1);
96 ASSERT_LONG_EQ(convtime("trout"), -1);
97 ASSERT_LONG_EQ(convtime("-77"), -1);
98 TEST_DONE();
99
100 TEST_START("dollar_expand");
101 if (setenv("FOO", "bar", 1) != 0)
102 abort();
103 if (setenv("BAR", "baz", 1) != 0)
104 abort();
105 if (unsetenv("BAZ") != 0)
106 abort();
107#define ASSERT_DOLLAR_EQ(x, y) do { \
108 char *str = dollar_expand(NULL, (x)); \
109 ASSERT_STRING_EQ(str, (y)); \
110 free(str); \
111} while(0)
112 ASSERT_DOLLAR_EQ("${FOO}", "bar");
113 ASSERT_DOLLAR_EQ(" ${FOO}", " bar");
114 ASSERT_DOLLAR_EQ("${FOO} ", "bar ");
115 ASSERT_DOLLAR_EQ(" ${FOO} ", " bar ");
116 ASSERT_DOLLAR_EQ("${FOO}${BAR}", "barbaz");
117 ASSERT_DOLLAR_EQ(" ${FOO} ${BAR}", " bar baz");
118 ASSERT_DOLLAR_EQ("${FOO}${BAR} ", "barbaz ");
119 ASSERT_DOLLAR_EQ(" ${FOO} ${BAR} ", " bar baz ");
120 ASSERT_DOLLAR_EQ("$", "$");
121 ASSERT_DOLLAR_EQ(" $", " $");
122 ASSERT_DOLLAR_EQ("$ ", "$ ");
123
124 /* suppress error messages for error handing tests */
125 log_init("test_misc", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 1);
126 /* error checking, non existent variable */
127 ret = dollar_expand(&parseerr, "a${BAZ}");
128 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
129 ret = dollar_expand(&parseerr, "${BAZ}b");
130 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
131 ret = dollar_expand(&parseerr, "a${BAZ}b");
132 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 0);
133 /* invalid format */
134 ret = dollar_expand(&parseerr, "${");
135 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
136 ret = dollar_expand(&parseerr, "${F");
137 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
138 ret = dollar_expand(&parseerr, "${FO");
139 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
140 /* empty variable name */
141 ret = dollar_expand(&parseerr, "${}");
142 ASSERT_PTR_EQ(ret, NULL); ASSERT_INT_EQ(parseerr, 1);
143 /* restore loglevel to default */
144 log_init("test_misc", SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 1);
145 TEST_DONE();
146
147 TEST_START("percent_expand");
148 ASSERT_STRING_EQ(percent_expand("%%", "%h", "foo", NULL), "%");
149 ASSERT_STRING_EQ(percent_expand("%h", "h", "foo", NULL), "foo");
150 ASSERT_STRING_EQ(percent_expand("%h ", "h", "foo", NULL), "foo ");
151 ASSERT_STRING_EQ(percent_expand(" %h", "h", "foo", NULL), " foo");
152 ASSERT_STRING_EQ(percent_expand(" %h ", "h", "foo", NULL), " foo ");
153 ASSERT_STRING_EQ(percent_expand(" %a%b ", "a", "foo", "b", "bar", NULL),
154 " foobar ");
155 TEST_DONE();
156
157 TEST_START("percent_dollar_expand");
158 ASSERT_STRING_EQ(percent_dollar_expand("%h${FOO}", "h", "foo", NULL),
159 "foobar");
160 TEST_DONE();
79} 161}
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 @@
1#!/bin/sh 1#!/bin/sh
2# $OpenBSD: mktestdata.sh,v 1.10 2020/05/01 04:03:14 djm Exp $ 2# $OpenBSD: mktestdata.sh,v 1.11 2020/06/19 03:48:49 djm Exp $
3 3
4PW=mekmitasdigoat 4PW=mekmitasdigoat
5 5
@@ -70,6 +70,15 @@ set -ex
70 70
71cd testdata 71cd testdata
72 72
73if [ -f ../../../misc/sk-dummy/sk-dummy.so ] ; then
74 SK_DUMMY=../../../misc/sk-dummy/sk-dummy.so
75elif [ -f ../../../misc/sk-dummy/obj/sk-dummy.so ] ; then
76 SK_DUMMY=../../../misc/sk-dummy/obj/sk-dummy.so
77else
78 echo "Can't find sk-dummy.so" 1>&2
79 exit 1
80fi
81
73rm -f rsa_1 dsa_1 ecdsa_1 ed25519_1 82rm -f rsa_1 dsa_1 ecdsa_1 ed25519_1
74rm -f rsa_2 dsa_2 ecdsa_2 ed25519_2 83rm -f rsa_2 dsa_2 ecdsa_2 ed25519_2
75rm -f rsa_n dsa_n ecdsa_n # new-format keys 84rm -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
81ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1 -m PEM 90ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1 -m PEM
82ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1 -m PEM 91ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1 -m PEM
83ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1 92ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1
93ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #1" \
94 -N "" -f ecdsa_sk1
95ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #1" \
96 -N "" -f ed25519_sk1
97
84 98
85ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2 -m PEM 99ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2 -m PEM
86ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2 -m PEM 100ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2 -m PEM
87ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2 -m PEM 101ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2 -m PEM
88ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_2 102ssh-keygen -t ed25519 -C "ED25519 test key #2" -N "" -f ed25519_2
103ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #2" \
104 -N "" -f ecdsa_sk2
105ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #2" \
106 -N "" -f ed25519_sk2
89 107
90cp rsa_1 rsa_n 108cp rsa_1 rsa_n
91cp dsa_1 dsa_n 109cp dsa_1 dsa_n
@@ -99,6 +117,8 @@ cp rsa_1 rsa_1_pw
99cp dsa_1 dsa_1_pw 117cp dsa_1 dsa_1_pw
100cp ecdsa_1 ecdsa_1_pw 118cp ecdsa_1 ecdsa_1_pw
101cp ed25519_1 ed25519_1_pw 119cp ed25519_1 ed25519_1_pw
120cp ecdsa_sk1 ecdsa_sk1_pw
121cp ed25519_sk1 ed25519_sk1_pw
102cp rsa_1 rsa_n_pw 122cp rsa_1 rsa_n_pw
103cp dsa_1 dsa_n_pw 123cp dsa_1 dsa_n_pw
104cp ecdsa_1 ecdsa_n_pw 124cp ecdsa_1 ecdsa_n_pw
@@ -107,6 +127,8 @@ ssh-keygen -pf rsa_1_pw -m PEM -N "$PW"
107ssh-keygen -pf dsa_1_pw -m PEM -N "$PW" 127ssh-keygen -pf dsa_1_pw -m PEM -N "$PW"
108ssh-keygen -pf ecdsa_1_pw -m PEM -N "$PW" 128ssh-keygen -pf ecdsa_1_pw -m PEM -N "$PW"
109ssh-keygen -pf ed25519_1_pw -N "$PW" 129ssh-keygen -pf ed25519_1_pw -N "$PW"
130ssh-keygen -pf ecdsa_sk1_pw -m PEM -N "$PW"
131ssh-keygen -pf ed25519_sk1_pw -N "$PW"
110ssh-keygen -pf rsa_n_pw -N "$PW" 132ssh-keygen -pf rsa_n_pw -N "$PW"
111ssh-keygen -pf dsa_n_pw -N "$PW" 133ssh-keygen -pf dsa_n_pw -N "$PW"
112ssh-keygen -pf ecdsa_n_pw -N "$PW" 134ssh-keygen -pf ecdsa_n_pw -N "$PW"
@@ -117,7 +139,7 @@ dsa_params dsa_1 dsa_1.param
117dsa_params dsa_1 dsa_1.param 139dsa_params dsa_1 dsa_1.param
118ecdsa_params ecdsa_1 ecdsa_1.param 140ecdsa_params ecdsa_1 ecdsa_1.param
119ecdsa_params ecdsa_2 ecdsa_2.param 141ecdsa_params ecdsa_2 ecdsa_2.param
120# XXX ed25519 params 142# XXX ed25519, *sk params
121 143
122ssh-keygen -s rsa_2 -I hugo -n user1,user2 \ 144ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
123 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \ 145 -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 \
131ssh-keygen -s rsa_2 -I hugo -n user1,user2 \ 153ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
132 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \ 154 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
133 -V 19990101:20110101 -z 4 ed25519_1.pub 155 -V 19990101:20110101 -z 4 ed25519_1.pub
156ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
157 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
158 -V 19990101:20110101 -z 4 ecdsa_sk1.pub
159ssh-keygen -s rsa_2 -I hugo -n user1,user2 \
160 -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \
161 -V 19990101:20110101 -z 4 ed25519_sk1.pub
162
134 163
135# Make a few RSA variant signature too. 164# Make a few RSA variant signature too.
136cp rsa_1 rsa_1_sha1 165cp rsa_1 rsa_1_sha1
@@ -152,30 +181,42 @@ ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
152 -V 19990101:20110101 -z 7 ecdsa_1.pub 181 -V 19990101:20110101 -z 7 ecdsa_1.pub
153ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \ 182ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
154 -V 19990101:20110101 -z 8 ed25519_1.pub 183 -V 19990101:20110101 -z 8 ed25519_1.pub
184ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \
185 -V 19990101:20110101 -z 7 ecdsa_sk1.pub
186ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \
187 -V 19990101:20110101 -z 8 ed25519_sk1.pub
155 188
156ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp 189ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp
157ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp 190ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp
158ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp 191ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp
159ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp 192ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp
193ssh-keygen -lf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp
194ssh-keygen -lf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp
160ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp 195ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp
161ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp 196ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp
162ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp 197ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp
163ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp 198ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp
199ssh-keygen -lf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp
200ssh-keygen -lf ed25519_sk2 | awk '{print $2}' > ed25519_sk2.fp
164 201
202ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp
165ssh-keygen -lf dsa_1-cert.pub | awk '{print $2}' > dsa_1-cert.fp 203ssh-keygen -lf dsa_1-cert.pub | awk '{print $2}' > dsa_1-cert.fp
166ssh-keygen -lf ecdsa_1-cert.pub | awk '{print $2}' > ecdsa_1-cert.fp 204ssh-keygen -lf ecdsa_1-cert.pub | awk '{print $2}' > ecdsa_1-cert.fp
167ssh-keygen -lf ed25519_1-cert.pub | awk '{print $2}' > ed25519_1-cert.fp 205ssh-keygen -lf ed25519_1-cert.pub | awk '{print $2}' > ed25519_1-cert.fp
168ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp 206ssh-keygen -lf ecdsa_sk1-cert.pub | awk '{print $2}' > ecdsa_sk1-cert.fp
207ssh-keygen -lf ed25519_sk1-cert.pub | awk '{print $2}' > ed25519_sk1-cert.fp
169 208
170ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb 209ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb
171ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb 210ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb
172ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb 211ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb
173ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb 212ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb
213ssh-keygen -Bf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp.bb
214ssh-keygen -Bf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp.bb
174ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb 215ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb
175ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb 216ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb
176ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb 217ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb
177ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb 218ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb
178 219ssh-keygen -Bf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp.bb
179# XXX Extend ssh-keygen to do detached signatures (better to test/fuzz against) 220ssh-keygen -Bf ed25519_sk2 | awk '{print $2}' > ed25519_sk2.fp.bb
180 221
181echo "$PW" > pw 222echo "$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 @@
1/* $OpenBSD: test_file.c,v 1.8 2018/09/13 09:03:20 djm Exp $ */ 1/* $OpenBSD: test_file.c,v 1.9 2020/06/19 03:48:49 djm Exp $ */
2/* 2/*
3 * Regress test for sshkey.h key management API 3 * Regress test for sshkey.h key management API
4 * 4 *
@@ -422,6 +422,137 @@ sshkey_file_tests(void)
422 422
423 sshkey_free(k1); 423 sshkey_free(k1);
424 424
425#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
426 TEST_START("parse ECDSA-SK from private");
427 buf = load_file("ecdsa_sk1");
428 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
429 sshbuf_free(buf);
430 ASSERT_PTR_NE(k1, NULL);
431 ASSERT_INT_EQ(k1->type, KEY_ECDSA_SK);
432 TEST_DONE();
433
434 TEST_START("parse ECDSA-SK from private w/ passphrase");
435 buf = load_file("ecdsa_sk1_pw");
436 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
437 (const char *)sshbuf_ptr(pw), &k2, NULL), 0);
438 sshbuf_free(buf);
439 ASSERT_PTR_NE(k2, NULL);
440 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
441 sshkey_free(k2);
442 TEST_DONE();
443
444 TEST_START("load ECDSA-SK from public");
445 ASSERT_INT_EQ(sshkey_load_public(test_data_file("ecdsa_sk1.pub"), &k2,
446 NULL), 0);
447 ASSERT_PTR_NE(k2, NULL);
448 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
449 sshkey_free(k2);
450 TEST_DONE();
451
452 TEST_START("load ECDSA-SK cert");
453 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ecdsa_sk1"), &k2), 0);
454 ASSERT_PTR_NE(k2, NULL);
455 ASSERT_INT_EQ(k2->type, KEY_ECDSA_SK_CERT);
456 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
457 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
458 TEST_DONE();
459
460 TEST_START("ECDSA-SK key hex fingerprint");
461 buf = load_text_file("ecdsa_sk1.fp");
462 cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA256, SSH_FP_BASE64);
463 ASSERT_PTR_NE(cp, NULL);
464 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
465 sshbuf_free(buf);
466 free(cp);
467 TEST_DONE();
468
469 TEST_START("ECDSA-SK cert hex fingerprint");
470 buf = load_text_file("ecdsa_sk1-cert.fp");
471 cp = sshkey_fingerprint(k2, SSH_DIGEST_SHA256, SSH_FP_BASE64);
472 ASSERT_PTR_NE(cp, NULL);
473 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
474 sshbuf_free(buf);
475 free(cp);
476 sshkey_free(k2);
477 TEST_DONE();
478
479 TEST_START("ECDSA-SK key bubblebabble fingerprint");
480 buf = load_text_file("ecdsa_sk1.fp.bb");
481 cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE);
482 ASSERT_PTR_NE(cp, NULL);
483 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
484 sshbuf_free(buf);
485 free(cp);
486 TEST_DONE();
487
488 sshkey_free(k1);
489#endif
490
491 TEST_START("parse Ed25519-SK from private");
492 buf = load_file("ed25519_sk1");
493 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0);
494 sshbuf_free(buf);
495 ASSERT_PTR_NE(k1, NULL);
496 ASSERT_INT_EQ(k1->type, KEY_ED25519_SK);
497 /* XXX check key contents */
498 TEST_DONE();
499
500 TEST_START("parse Ed25519-SK from private w/ passphrase");
501 buf = load_file("ed25519_sk1_pw");
502 ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf,
503 (const char *)sshbuf_ptr(pw), &k2, NULL), 0);
504 sshbuf_free(buf);
505 ASSERT_PTR_NE(k2, NULL);
506 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
507 sshkey_free(k2);
508 TEST_DONE();
509
510 TEST_START("load Ed25519-SK from public");
511 ASSERT_INT_EQ(sshkey_load_public(test_data_file("ed25519_sk1.pub"),
512 &k2, NULL), 0);
513 ASSERT_PTR_NE(k2, NULL);
514 ASSERT_INT_EQ(sshkey_equal(k1, k2), 1);
515 sshkey_free(k2);
516 TEST_DONE();
517
518 TEST_START("load Ed25519-SK cert");
519 ASSERT_INT_EQ(sshkey_load_cert(test_data_file("ed25519_sk1"), &k2), 0);
520 ASSERT_PTR_NE(k2, NULL);
521 ASSERT_INT_EQ(k2->type, KEY_ED25519_SK_CERT);
522 ASSERT_INT_EQ(sshkey_equal(k1, k2), 0);
523 ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1);
524 TEST_DONE();
525
526 TEST_START("Ed25519-SK key hex fingerprint");
527 buf = load_text_file("ed25519_sk1.fp");
528 cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA256, SSH_FP_BASE64);
529 ASSERT_PTR_NE(cp, NULL);
530 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
531 sshbuf_free(buf);
532 free(cp);
533 TEST_DONE();
534
535 TEST_START("Ed25519-SK cert hex fingerprint");
536 buf = load_text_file("ed25519_sk1-cert.fp");
537 cp = sshkey_fingerprint(k2, SSH_DIGEST_SHA256, SSH_FP_BASE64);
538 ASSERT_PTR_NE(cp, NULL);
539 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
540 sshbuf_free(buf);
541 free(cp);
542 sshkey_free(k2);
543 TEST_DONE();
544
545 TEST_START("Ed25519-SK key bubblebabble fingerprint");
546 buf = load_text_file("ed25519_sk1.fp.bb");
547 cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE);
548 ASSERT_PTR_NE(cp, NULL);
549 ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf));
550 sshbuf_free(buf);
551 free(cp);
552 TEST_DONE();
553
554 sshkey_free(k1);
555
425 sshbuf_free(pw); 556 sshbuf_free(pw);
426 557
427} 558}
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 @@
1/* $OpenBSD: test_fuzz.c,v 1.11 2019/11/25 10:32:35 djm Exp $ */ 1/* $OpenBSD: test_fuzz.c,v 1.12 2020/08/27 03:55:22 djm Exp $ */
2/* 2/*
3 * Fuzz tests for key parsing 3 * Fuzz tests for key parsing
4 * 4 *
@@ -88,7 +88,7 @@ sig_fuzz(struct sshkey *k, const char *sig_alg)
88 fuzzers |= FUZZ_2_BIT_FLIP; 88 fuzzers |= FUZZ_2_BIT_FLIP;
89 89
90 ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c), 90 ASSERT_INT_EQ(sshkey_sign(k, &sig, &l, c, sizeof(c),
91 sig_alg, NULL, 0), 0); 91 sig_alg, NULL, NULL, 0), 0);
92 ASSERT_SIZE_T_GT(l, 0); 92 ASSERT_SIZE_T_GT(l, 0);
93 fuzz = fuzz_begin(fuzzers, sig, l); 93 fuzz = fuzz_begin(fuzzers, sig, l);
94 ASSERT_INT_EQ(sshkey_verify(k, sig, l, c, sizeof(c), NULL, 0, NULL), 0); 94 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 @@
1/* $OpenBSD: test_sshkey.c,v 1.20 2019/11/25 10:32:35 djm Exp $ */ 1/* $OpenBSD: test_sshkey.c,v 1.21 2020/08/27 03:55:22 djm Exp $ */
2/* 2/*
3 * Regress test for sshkey.h key management API 3 * Regress test for sshkey.h key management API
4 * 4 *
@@ -101,7 +101,7 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type,
101 ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ 101 ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */
102 ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ 102 ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */
103 ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, 103 ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen,
104 sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, 0), 0); 104 sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0);
105 ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ 105 ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */
106 106
107 free(sigblob); 107 free(sigblob);
@@ -120,7 +120,8 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg,
120 size_t len; 120 size_t len;
121 u_char *sig; 121 u_char *sig;
122 122
123 ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, 0), 0); 123 ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg,
124 NULL, NULL, 0), 0);
124 ASSERT_SIZE_T_GT(len, 8); 125 ASSERT_SIZE_T_GT(len, 8);
125 ASSERT_PTR_NE(sig, NULL); 126 ASSERT_PTR_NE(sig, NULL);
126 ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); 127 ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
@@ -437,7 +438,7 @@ sshkey_tests(void)
437 put_opt(k1->cert->extensions, "permit-X11-forwarding", NULL); 438 put_opt(k1->cert->extensions, "permit-X11-forwarding", NULL);
438 put_opt(k1->cert->extensions, "permit-agent-forwarding", NULL); 439 put_opt(k1->cert->extensions, "permit-agent-forwarding", NULL);
439 ASSERT_INT_EQ(sshkey_from_private(k2, &k1->cert->signature_key), 0); 440 ASSERT_INT_EQ(sshkey_from_private(k2, &k1->cert->signature_key), 0);
440 ASSERT_INT_EQ(sshkey_certify(k1, k2, NULL, NULL), 0); 441 ASSERT_INT_EQ(sshkey_certify(k1, k2, NULL, NULL, NULL), 0);
441 b = sshbuf_new(); 442 b = sshbuf_new();
442 ASSERT_PTR_NE(b, NULL); 443 ASSERT_PTR_NE(b, NULL);
443 ASSERT_INT_EQ(sshkey_putb(k1, b), 0); 444 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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
3RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQRnVT5Cji1D
4Ge2+q2X0vATh6LYnODV+DJrshJorr5GnipW29RfuaDXs0WB6XBej9dOLazVRDjQrtV19Qg
5O6cfkFAAAABHNzaDoAAAGQuPdnP7j3Zz8AAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
6cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEZ1U+Qo4tQxntvqtl9LwE4ei2Jzg1fgya7I
7SaK6+Rp4qVtvUX7mg17NFgelwXo/XTi2s1UQ40K7VdfUIDunH5BQAAAARzc2g6AQAAAOMt
8LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJRURmVFB4YzA0alN5Zk
9Z5NlhoV1pTVlpzcnU5ZFlaSVpTOWhjeVFhcDlVT29Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
10QUVaMVUrUW80dFF4bnR2cXRsOUx3RTRlaTJKemcxZmd5YTdJU2FLNitScDRxVnR2VVg3bW
11cxCjdORmdlbHdYby9YVGkyczFVUTQwSzdWZGZVSUR1bkg1QlE9PQotLS0tLUVORCBFQyBQ
12UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAURUNEU0EtU0sgdGVzdCBrZXkgIzEBAgMEBQ==
13-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB6vcJVx2
3cPc7yYRROup8VnAAAAEAAAAAEAAAB/AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3Bl
4bnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGdVPkKOLUMZ7b6rZfS8BOHotic4NX4MmuyEmi
5uvkaeKlbb1F+5oNezRYHpcF6P104trNVEONCu1XX1CA7px+QUAAAAEc3NoOgAAAZBrvCxe
6xFz0bvzXwaPhrUHBeNCoZy/wNKDx0kxlxUPuA+lgOvy5l3lT3yxxd0qj5PQB+NTcuz8AAE
71f7aSWQNZSifox3COsBGoHV9C8i+glcxiBKheAZD+EBnRGjG8kbcaLhuYDW/I39qNe8lHW
8YSDjmvsT55Hy0IAtVRAXizDoXKNdFPTZisC67WyOSJ3ED7Fy4bfT4ApbvhoFTwjikZBEhy
9LOad1sbJa4eT19TsskYfQdnJf8sjAmCMOZY4ZV0FiNW5XZOp8nIal1oyULPfzTAm6oaeFN
100ImCSU3U8h4wUQ8q/3XvBWtTKycZaoou0AwPoP0QN95Ywte7FHezNPb/n8KD7k0S6h9XAX
11UcBeCe5NHyov/0ZzA2p737hzm3w+MXGOboTQMu8WFXeGh4m7QH2o8ZJdgBhM5JF17uii+Q
12ppGoPWHf33MXwB3wxWmKZ0ua0f9AVLkQ2DfFszUoBJE/kcHRd4kj4Q4FWXeMBN0GoH8gdE
13gRWIlxn2/FAOce/BFPzzdP87H0jwz7SdcuVO1L
14-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
3RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQSTl+SR6rTg
4lOZmcQkCtJ3Pd+lWinezo/gHk4oZdZcTQsmEYs766BlWGuB2Bz3qQRLa6cXsP+4K9kAjAJ
57zdoFUAAAABHNzaDoAAAGQ1qllJtapZSYAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
6cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEk5fkkeq04JTmZnEJArSdz3fpVop3s6P4B5
7OKGXWXE0LJhGLO+ugZVhrgdgc96kES2unF7D/uCvZAIwCe83aBVAAAAARzc2g6AQAAAOMt
8LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJSkxwVkxnSTVvdkRlOW
9VMWmZodCs5WWlMaitnam0rTXhHTXg5NndiRWw0Wm9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
10QUVrNWZra2VxMDRKVG1abkVKQXJTZHozZnBWb3AzczZQNEI1T0tHWFdYRTBMSmhHTE8rdW
11daClZocmdkZ2M5NmtFUzJ1bkY3RC91Q3ZaQUl3Q2U4M2FCVkE9PQotLS0tLUVORCBFQyBQ
12UklWQVRFIEtFWS0tLS0tCgAAAAAAAAAURUNEU0EtU0sgdGVzdCBrZXkgIzIBAgMEBQ==
13-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
3gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACAhaP5OS1PPOt7uumAvXlDtte9EHbqIT1EZEJ2y
42v3XMwAAAARzc2g6AAAAuBocY6UaHGOlAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
59tAAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDoBAAAAQJYq
6lGHhFoA25/q8X/rdTqDAb7dhqs4ehhd/w8x99CwiIWj+TktTzzre7rpgL15Q7bXvRB26iE
79RGRCdstr91zMAAAAAAAAAFkVEMjU1MTktU0sgdGVzdCBrZXkgIzEBAgM=
8-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDr5R9Yf/
3ucEh0Ns6c34tcIAAAAEAAAAAEAAABKAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t
4AAAAICFo/k5LU8863u66YC9eUO2170QduohPURkQnbLa/dczAAAABHNzaDoAAADA2T6owx
5OSgKz4DvLnS3UJ/renbuew5mbkIWB1/y8xd3y5Usm08iUCAlKxep9dVRQvmyoTrc/7rHOM
6DkokNw+WgKambnlYT/9QfqViZ9iCBtbdmhLM6ksUCgQefvquRyXoJxlWstjXUll6Ru+ZbT
7H//Ss8C1bYtAiXR68OQ+rhDrvQxA9P8J1sGIlkuV3h8YXddSpyBW2Sn0LTHHBXYZo86cXZ
8G4Lnc8aGYm65eqdHgkfRmht3eS8DTdzEBfBNH5Ml
9-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
3gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACAV8fu1Sc31QLK2R/zGPdN3ve5xuFvDc7mEAWxb
4aI+YcwAAAARzc2g6AAAAuJCMX5uQjF+bAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
59tAAAAIBXx+7VJzfVAsrZH/MY903e97nG4W8NzuYQBbFtoj5hzAAAABHNzaDoBAAAAQObE
6PajcKI1W30EKOhBb6u+Fgx464kf7EjnqDSg4l7gAFfH7tUnN9UCytkf8xj3Td73ucbhbw3
7O5hAFsW2iPmHMAAAAAAAAAFkVEMjU1MTktU0sgdGVzdCBrZXkgIzIBAgM=
8-----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..4b607df45
--- /dev/null
+++ b/regress/unittests/sshsig/Makefile
@@ -0,0 +1,25 @@
1# $OpenBSD: Makefile,v 1.1 2020/06/19 04:32:09 djm Exp $
2
3PROG=test_sshsig
4SRCS=tests.c
5
6# From usr.bin/ssh
7SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c
8SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c
9SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c
10SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c
11SRCS+=addrmatch.c bitmap.c sshsig.c
12SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c
13SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c
14SRCS+=ssh-ed25519-sk.c sk-usbhid.c
15
16SRCS+=digest-openssl.c
17#SRCS+=digest-libc.c
18SRCS+=utf8.c
19
20REGRESS_TARGETS=run-regress-${PROG}
21
22run-regress-${PROG}: ${PROG}
23 env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata
24
25.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 @@
1#!/bin/sh
2# $OpenBSD: mktestdata.sh,v 1.1 2020/06/19 04:32:09 djm Exp $
3
4NAMESPACE=unittest
5
6set -ex
7
8cd testdata
9
10if [ -f ../../../misc/sk-dummy/sk-dummy.so ] ; then
11 SK_DUMMY=../../../misc/sk-dummy/sk-dummy.so
12elif [ -f ../../../misc/sk-dummy/obj/sk-dummy.so ] ; then
13 SK_DUMMY=../../../misc/sk-dummy/obj/sk-dummy.so
14else
15 echo "Can't find sk-dummy.so" 1>&2
16 exit 1
17fi
18
19rm -f signed-data namespace
20rm -f rsa dsa ecdsa ed25519 ecdsa_sk ed25519_sk
21rm -f rsa.sig dsa.sig ecdsa.sig ed25519.sig ecdsa_sk.sig ed25519_sk.sig
22
23printf "This is a test, this is only a test" > signed-data
24printf "$NAMESPACE" > namespace
25
26ssh-keygen -t rsa -C "RSA test" -N "" -f rsa -m PEM
27ssh-keygen -t dsa -C "DSA test" -N "" -f dsa -m PEM
28ssh-keygen -t ecdsa -C "ECDSA test" -N "" -f ecdsa -m PEM
29ssh-keygen -t ed25519 -C "ED25519 test key" -N "" -f ed25519
30ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key" \
31 -N "" -f ecdsa_sk
32ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key" \
33 -N "" -f ed25519_sk
34
35ssh-keygen -Y sign -f rsa -n $NAMESPACE - < signed-data > rsa.sig
36ssh-keygen -Y sign -f dsa -n $NAMESPACE - < signed-data > dsa.sig
37ssh-keygen -Y sign -f ecdsa -n $NAMESPACE - < signed-data > ecdsa.sig
38ssh-keygen -Y sign -f ed25519 -n $NAMESPACE - < signed-data > ed25519.sig
39ssh-keygen -w "$SK_DUMMY" \
40 -Y sign -f ecdsa_sk -n $NAMESPACE - < signed-data > ecdsa_sk.sig
41ssh-keygen -w "$SK_DUMMY" \
42 -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 @@
1-----BEGIN DSA PRIVATE KEY-----
2MIIBuwIBAAKBgQCXpndQdz2mQVnk+lYOF3nxDT+h6SiJmUvBFhnFWBv8tG4pTOkb
3EwGufLEzGpzjTj+3bjVau7LFt37AFrqs4Num272BWNsYNIjOlGPgq7Xjv32FN00x
4JYh1DoRs1cGGnvohlsWEamGGhTHD1a9ipctPEBV+NrxtZMrl+pO/ZZg8vQIVAKJB
5P3iNYSpSuW74+q4WxLCuK8O3AoGAQldE+BIuxlvoG1IFiWesx0CU+H2KO0SEZc9A
6SX/qjOabh0Fb78ofTlEf9gWHFfat8SvSJQIOPMVlb76Lio8AAMT8Eaa/qQKKYmQL
7dNq4MLhhjxx5KLGt6J2JyFPExCv+qnHYHD59ngtLwKyqGjpSC8LPLktdXn8W/Aad
8Ly1K7+MCgYBsMHBczhSeUh8w7i20CVg4OlNTmfJRVU2tO6OpMxZ/quitRm3hLKSN
9u4xRkvHJwi4LhQtv1SXvLI5gs5P3gCG8tsIAiyCqLinHha63iBdJpqhnV/x/j7dB
10yJr3xJbnmLdWLkkCtNk1Ir1/CuEz+ufAyLGdKWksEAu1UUlb501BkwIVAILIa3Rg
110h7J9lQpHJphvF3K0M1T
12-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAbEAAAAHc3NoLWRzcwAAAIEAl6Z3UHc9pkFZ5PpWDhd58Q0/oekoiZ
3lLwRYZxVgb/LRuKUzpGxMBrnyxMxqc404/t241Wruyxbd+wBa6rODbptu9gVjbGDSIzpRj
44Ku14799hTdNMSWIdQ6EbNXBhp76IZbFhGphhoUxw9WvYqXLTxAVfja8bWTK5fqTv2WYPL
50AAAAVAKJBP3iNYSpSuW74+q4WxLCuK8O3AAAAgEJXRPgSLsZb6BtSBYlnrMdAlPh9ijtE
6hGXPQEl/6ozmm4dBW+/KH05RH/YFhxX2rfEr0iUCDjzFZW++i4qPAADE/BGmv6kCimJkC3
7TauDC4YY8ceSixreidichTxMQr/qpx2Bw+fZ4LS8Csqho6UgvCzy5LXV5/FvwGnS8tSu/j
8AAAAgGwwcFzOFJ5SHzDuLbQJWDg6U1OZ8lFVTa07o6kzFn+q6K1GbeEspI27jFGS8cnCLg
9uFC2/VJe8sjmCzk/eAIby2wgCLIKouKceFrreIF0mmqGdX/H+Pt0HImvfElueYt1YuSQK0
102TUivX8K4TP658DIsZ0paSwQC7VRSVvnTUGTAAAACHVuaXR0ZXN0AAAAAAAAAAZzaGE1MT
11IAAAA3AAAAB3NzaC1kc3MAAAAodi5lr0pqBpO76OY4N1CtfR85BCgZ95qfVjP/e9lToj0q
12lwjSJJXUjw==
13-----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 @@
1-----BEGIN EC PRIVATE KEY-----
2MHcCAQEEIFg0ZCSEB5LNeLsXYL25g3kqEWsqh52DR+yNOjyQJqyZoAoGCCqGSM49
3AwEHoUQDQgAE3sud88FV0N8FPspZSV7LWqj6uPPLRZiSsenNuEYAteWPyDgrZsWb
4LzXBuUJucepaCNuW/QWgHBRbrjWj3ERm3A==
5-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAE
3EE3sud88FV0N8FPspZSV7LWqj6uPPLRZiSsenNuEYAteWPyDgrZsWbLzXBuUJucepaCNuW
4/QWgHBRbrjWj3ERm3AAAAAh1bml0dGVzdAAAAAAAAAAGc2hhNTEyAAAAZQAAABNlY2RzYS
51zaGEyLW5pc3RwMjU2AAAASgAAACEAycVNsTlE+XEZYyYiDxWZlliruf/pPMhEEMR/XLdQ
6a4MAAAAhALQt+5gES7L3uKGptHB6UZQMuZ2WyI0C6FJs4v6AtMIU
7-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
3RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQSg1WuY0XE+
4VexOsrJsFYuxyVoe6eQ/oXmyz2pEHKZw9moyWehv+Fs7oZWFp3JVmOtybKQ6dvfUZYauQE
5/Ov4PAAAAABHNzaDoAAAGI6iV41+oleNcAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
6cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEoNVrmNFxPlXsTrKybBWLsclaHunkP6F5ss
79qRBymcPZqMlnob/hbO6GVhadyVZjrcmykOnb31GWGrkBPzr+DwAAAAARzc2g6AQAAAOMt
8LS0tLUJFR0lOIEVDIFBSSVZBVEUgS0VZLS0tLS0KTUhjQ0FRRUVJQm9oeW54M2tpTFVEeS
9t5UjU3WXBXSU5KektnU1p6WnV2VTljYXFla3JGcW9Bb0dDQ3FHU000OQpBd0VIb1VRRFFn
10QUVvTlZybU5GeFBsWHNUckt5YkJXTHNjbGFIdW5rUDZGNXNzOXFSQnltY1BacU1sbm9iL2
11hiCk82R1ZoYWR5VlpqcmNteWtPbmIzMUdXR3JrQlB6citEd0E9PQotLS0tLUVORCBFQyBQ
12UklWQVRFIEtFWS0tLS0tCgAAAAAAAAARRUNEU0EtU0sgdGVzdCBrZXk=
13-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAH8AAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBvcGVuc3NoLmNvbQ
3AAAAhuaXN0cDI1NgAAAEEEoNVrmNFxPlXsTrKybBWLsclaHunkP6F5ss9qRBymcPZqMlno
4b/hbO6GVhadyVZjrcmykOnb31GWGrkBPzr+DwAAAAARzc2g6AAAACHVuaXR0ZXN0AAAAAA
5AAAAZzaGE1MTIAAAB3AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20A
6AABIAAAAIHohGwyy8iKT3zwd1TYA9V/Ioo7h/3zCJUtyq/Qigt/HAAAAIGzidTwq7D/kFa
77Xjcp/KkdbIs4MfQpfAW/0OciajlpzARI0Vng=
8-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAIYAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBvcGVuc3NoLmNvbQ
3AAAAhuaXN0cDI1NgAAAEEEFEbAOOzgeEkVyfi0nkavvYpyZGYJLU6KsRPFpe+ew0CmCg4s
4XVr/uvGV19Iwebvd5PWeEd73tbyqJw88QAoMlAAAAAttaW5kcm90Lm9yZwAAAAh1bml0dG
5VzdAAAAAAAAAAGc2hhNTEyAAABhwAAACt3ZWJhdXRobi1zay1lY2RzYS1zaGEyLW5pc3Rw
6MjU2QG9wZW5zc2guY29tAAAASQAAACBj2oMT9tb5wRXe6mdmf4/lgAO8wrgr95ouozwNg4
7itnQAAACEAtU9g5wz3HchUiLfLD6plr9T4TiJ32lVCrATSjpiy0SMBAAADHwAAABdodHRw
8czovL3d3dy5taW5kcm90Lm9yZwAAAON7InR5cGUiOiJ3ZWJhdXRobi5nZXQiLCJjaGFsbG
9VuZ2UiOiJVMU5JVTBsSEFBQUFDSFZ1YVhSMFpYTjBBQUFBQUFBQUFBWnphR0UxTVRJQUFB
10QkFMTHU4WmdjU3h0Nk1zRlV6dWlaZ0c2R3dNZEo5ZDd4ZUU3WW9SSXcwZzlpSEpfd3NGRD
11cxbzRXbHllenZGV0VqYnFRMHFDN0Z3R3Bqa2pVUVAtTmQ2dyIsIm9yaWdpbiI6Imh0dHBz
12Oi8vd3d3Lm1pbmRyb3Qub3JnIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQAAAAA=
13-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3QyNTUxOQAAACCJYs0iDdw0Fe/FTzY1b78I4H/j+R6mz2AmLtwTjHYwBAAAAJjpGas/6Rmr
4PwAAAAtzc2gtZWQyNTUxOQAAACCJYs0iDdw0Fe/FTzY1b78I4H/j+R6mz2AmLtwTjHYwBA
5AAAEDpSKRA1QKW6kYiQftGRWh+H0fNekzYLG6c3bzseoCpEolizSIN3DQV78VPNjVvvwjg
6f+P5HqbPYCYu3BOMdjAEAAAAEEVEMjU1MTkgdGVzdCBrZXkBAgMEBQ==
7-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgiWLNIg3cNBXvxU82NW+/COB/4/
3keps9gJi7cE4x2MAQAAAAIdW5pdHRlc3QAAAAAAAAABnNoYTUxMgAAAFMAAAALc3NoLWVk
4MjU1MTkAAABAihQsbUzuNEFflk5Tw1+H9aLS7tZQk0RG8KW1DtOmDYYnWe3D3UKiG3fcJa
5DNg4vBWp1j1gLRiBMOF+gwYNegDg==
6-----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 @@
1-----BEGIN OPENSSH PRIVATE KEY-----
2b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
3gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACCbGg2F0GK7nOm4pQmAyCuGEjnhvs5q0TtjPbdN
4//+yxwAAAARzc2g6AAAAuBw56jAcOeowAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
59tAAAAIJsaDYXQYruc6bilCYDIK4YSOeG+zmrRO2M9t03//7LHAAAABHNzaDoBAAAAQFXc
66dCwWewIk1EBofAouGZApW8+s0XekXenxtb78+x0mxoNhdBiu5zpuKUJgMgrhhI54b7Oat
7E7Yz23Tf//sscAAAAAAAAAE0VEMjU1MTktU0sgdGVzdCBrZXkBAgMEBQY=
8-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAEoAAAAac2stc3NoLWVkMjU1MTlAb3BlbnNzaC5jb20AAAAgmxoNhd
3Biu5zpuKUJgMgrhhI54b7OatE7Yz23Tf//sscAAAAEc3NoOgAAAAh1bml0dGVzdAAAAAAA
4AAAGc2hhNTEyAAAAZwAAABpzay1zc2gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAAEAi+7eTjW
5/+LQ2M+sCD+KFtH1n7VFFJon/SZFsxODyV8cWTlFKj617Ys1Ur5TV6uaEXQhck8rBA2oQI
6HTPANLIPARI0Vng=
7-----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 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIIG4wIBAAKCAYEA386lmjRHtJpyj87BrS+ssMmtvc/1SPN0gXTPs9jZ1hYAq98P
3ca3/RYVM4HaSu6COztQJ2ZnZD3Te/XeBnIU2mfuvQEl+DiwisGeNglVyRCi7787f
4PFFfcxzZfDa7EB2qY8S3oaSGZK8QqzuGwmGAImjlQXz6J+HCd/eD/58GoCSSirIE
5CFWCAt+uNrOC/EmgAzsbfcfaIbbVzA40tlgU3hO2J42kddz8CisDTtDKQABFcOaQ
6ZycSfn7HDP+WgXLXXBUI9wVM1Tif1f+9MX08xIsvCvGzo7yLgbbTFLSGr5SkA+tO
7rYuoA7V8fge0id/3pnVtG1Ui3I7vejeAwf0HZqtFeBEnOwkIJFmZeMtFeOVf+4ki
84h1rDqAvSscNvMtLp6OXpbAATATAuEWEkIQBl1rngnEe0iC9iU9itKMW6qJ4FtIb
94ACH1EoU1x8vqrFecg2hvqfk5CZBJIbV28JFuGjac3OxBZ17Fqb8ljomUir1GrET
102z66NMgb5TjDD7BVAgMBAAECggGACfjDGCPMLhfTkuS7bGP7ZcUWoKZrX1y5jCsQ
11NgsraYaBcSb3ITGHdimCS139G68DreN0rOVV7oJejRyOAdNNo367SDn+C9ObmBCF
12FZGJDdBiz0SAXceiYRaf+hDWNNmdheR16hXShxnlvDtivbZqZx4VWN2gp7Y/W+kD
13UJhdSzVV8igMVfK5YDdnI7jL1UHSh1JS3z/QUEA9NmJLpvQ1uc9XBlwhP78g27Me
146pwS5tccQPOE65OqF0i+xa19nzbmnC940Y34yZeI/UE+PYaO2+asapvOfu/sboBH
15Yb5BuWXVEkSeRWI23SpuZbmfNTtVgiRoRqOvqM4G88LkhYjZ6xpDggxQwJiShiiD
16oWCucs0v3pX8H8/LbGs8l50SGI5nzUqAdZ7/QQucU/GuDiQtampntkLEDgf9KIw/
17SDrtCw1E9fnCWj4Z71IYfepY9bVY6QUEcfTdnDcYSY1Z5tVpzeMHVLeo0lbNVZv9
182qmPnjjP/IvWbjjwu/PHpUWkUs0BAoHBAPx4YwPXWYgWnesMKXkjAHyO5KA4EyBr
19+rcEmOZkZDibC8PKYzIK2ztptuthahVovW20R/QJhJkO5teGZMeGPFq+floCeC5P
20la9CEYGYcTrzgSe1QM9IGMr1vGI1KIWck7VkJ0bkKoY40uIJSVZxnyG9pEpcwYSp
21tnOqA/f5YZUFctWvXUz46OfiLKstXLrcrGIU7YRmLv2rW9twnpJYTzE98g3KpVJ2
22TI1pyvrDTdGeAQUTGCAjpviY6XR5d020vQKBwQDi76wsGLQ3XLI+OAE95Ljo0Mcl
23+KdJPVVQPq/VcjKgZQndFloflMRrmgNHme9gmsHOrf8DLZvEDbtT+gbmWslMFZQ9
24om1kR404gfuGmfIYdBdOwWjuBLsZs3pfqDB4Xa3NkxljwOMYTp035n0r2UMFaSy3
25gvpW7fsdPOGAJsqNhSw/JNHcokHeBm7VbV0aD7tSyIghmARb5c98fmrSPbiEo8mP
26ITIZlgbfZCq2KuXY4q16R3QvlpuSwitVobLR/3kCgcEAueH5JM7dQHFGe9RMhL/c
27j9i1Q7GFg4183lsoKBkqIPMmylSsjB+qIihHYS4r6O9g6PCfOXH4iqiKFY0BjlWr
28AjTW2naO/aniz1KZiQ0v8PNv2Eh/Gx4+AtDCjpwM5bLOnfLLaEp9dK1JttqXgGnP
29fAwgdg+s+3votWgr29tkmU+VqPagfxeUg4Xm1XFkoL/wu5Yk+iIx3trXms1kMuOK
30CvtMyBK3fetTmZqWs+Iv3XGz1oSkcqVNPiN3XyY/TJsRAoG/Q17jvjOXTNg4EkCO
31HdHJE1Tnyl4HS7bpnOj/Sl6cqQFV7Ey2dKm1pjwSvS714bgP0UvWaRshIxLwif2w
32DrLlD7FYUPPnhd24Dw6HnW4WcSwFv1uryv2cjgS6T6ueuB0Xe/AvmW2p/Y1ZHz9N
336baWLwUKQXCg4S3FXui0CVd6yoi+mgBUTSveYguG29WbziDde7YMs+xtXtravhrJ
34m6C3Jql5LQSt2uqvH6KdC3ewxLKGzcZot7f+d5MtSj6216ECgcEA9PGmWeUkhVuW
35Xz2c9iBeHwCtmDso7gVwxNnHqdqirB4f1nDCGbrJS7hz5Ss7/wfzekP2W5if2P6U
36JPUdfykAQgALNn1twAtj1a+UAp31ZWu8JK/Qzt4hLJPBxzMo7MenJq189JmYmDnm
376D5d9vDLCW15gCZua89GZa8K8V50lYyeHBOHAyzNTfNlnMBkHyP645+nqpuEWzIT
383mCe2OAbl60o8VvvVUlAQyQ/ObLq37HHEoDu0U/YAnP157cxpa84
39-----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 @@
1-----BEGIN SSH SIGNATURE-----
2U1NIU0lHAAAAAQAAAZcAAAAHc3NoLXJzYQAAAAMBAAEAAAGBAN/OpZo0R7Saco/Owa0vrL
3DJrb3P9UjzdIF0z7PY2dYWAKvfD3Gt/0WFTOB2krugjs7UCdmZ2Q903v13gZyFNpn7r0BJ
4fg4sIrBnjYJVckQou+/O3zxRX3Mc2Xw2uxAdqmPEt6GkhmSvEKs7hsJhgCJo5UF8+ifhwn
5f3g/+fBqAkkoqyBAhVggLfrjazgvxJoAM7G33H2iG21cwONLZYFN4TtieNpHXc/AorA07Q
6ykAARXDmkGcnEn5+xwz/loFy11wVCPcFTNU4n9X/vTF9PMSLLwrxs6O8i4G20xS0hq+UpA
7PrTq2LqAO1fH4HtInf96Z1bRtVItyO73o3gMH9B2arRXgRJzsJCCRZmXjLRXjlX/uJIuId
8aw6gL0rHDbzLS6ejl6WwAEwEwLhFhJCEAZda54JxHtIgvYlPYrSjFuqieBbSG+AAh9RKFN
9cfL6qxXnINob6n5OQmQSSG1dvCRbho2nNzsQWdexam/JY6JlIq9RqxE9s+ujTIG+U4ww+w
10VQAAAAh1bml0dGVzdAAAAAAAAAAGc2hhNTEyAAABlAAAAAxyc2Etc2hhMi01MTIAAAGACi
11nEpBrQxZi0yOrrT6h98JFfZh0XXioih4fzmvtoV0yOReWClS+otGgXoJyZHcbaKNOjDwSM
12rIkUoX6OUJmtHYP0HRELnKw35m33LdBPXpFGS4tRS7NeSpvc04KtjT6jYXY9FjWy5hcn17
13Sxc/3DnJqLgJBur8acY7FeIzpWmKixPd/dGkEjdWoD9gO6szLczGuQgrOdYmSRL4yKadTJ
14lVjz5OSeKSYYGQy33US2XQassRRNYf4e9byTA3DKvHa/OcTt7lFerea0kZdDpAboqffz7T
15Yaw/hFskAYLIEdTW3aoXBGHSOvu8AkDOtb7qwuxGSQ27pjkDLDNsp1ceCFaCaQ6X83RZuK
16ACv9JUBI5KaSf81e0bs0KezJKkhB9czeZ6dk96qISbgayEBnvhYgXvUDKtHn7HzNlCJKfK
175ABhNxfGG2CD+NKqcrndwFgS1sQO3hbA84zPQb26ShBovT8ytHBmW1F8ZK4O9Bz61Q6EZK
18vs/u6xP6LUean/so5daa
19-----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 @@
1/* $OpenBSD: tests.c,v 1.2 2020/06/22 06:00:06 djm Exp $ */
2/*
3 * Regress test for sshbuf.h buffer API
4 *
5 * Placed in the public domain
6 */
7
8#include "includes.h"
9
10#include <sys/types.h>
11#include <sys/param.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <stdio.h>
15#ifdef HAVE_STDINT_H
16#include <stdint.h>
17#endif
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <openssl/evp.h>
23#include <openssl/crypto.h>
24
25#include "ssherr.h"
26#include "authfile.h"
27#include "sshkey.h"
28#include "sshbuf.h"
29#include "sshsig.h"
30#include "log.h"
31
32#include "../test_helper/test_helper.h"
33
34static struct sshbuf *
35load_file(const char *name)
36{
37 struct sshbuf *ret = NULL;
38
39 ASSERT_INT_EQ(sshbuf_load_file(test_data_file(name), &ret), 0);
40 ASSERT_PTR_NE(ret, NULL);
41 return ret;
42}
43
44static struct sshkey *
45load_key(const char *name)
46{
47 struct sshkey *ret = NULL;
48 ASSERT_INT_EQ(sshkey_load_public(test_data_file(name), &ret, NULL), 0);
49 ASSERT_PTR_NE(ret, NULL);
50 return ret;
51}
52
53static void
54check_sig(const char *keyname, const char *signame, const struct sshbuf *msg,
55 const char *namespace)
56{
57 struct sshkey *k, *sign_key;
58 struct sshbuf *sig, *rawsig;
59 struct sshkey_sig_details *sig_details;
60
61 k = load_key(keyname);
62 sig = load_file(signame);
63 sign_key = NULL;
64 sig_details = NULL;
65 rawsig = NULL;
66 ASSERT_INT_EQ(sshsig_dearmor(sig, &rawsig), 0);
67 ASSERT_INT_EQ(sshsig_verifyb(rawsig, msg, namespace,
68 &sign_key, &sig_details), 0);
69 ASSERT_INT_EQ(sshkey_equal(k, sign_key), 1);
70 sshkey_free(k);
71 sshkey_free(sign_key);
72 sshkey_sig_details_free(sig_details);
73 sshbuf_free(sig);
74 sshbuf_free(rawsig);
75}
76
77void
78tests(void)
79{
80 struct sshbuf *msg;
81 char *namespace;
82
83#if 0
84 log_init("test_sshsig", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
85#endif
86
87#ifdef WITH_OPENSSL
88 OpenSSL_add_all_algorithms();
89 ERR_load_CRYPTO_strings();
90#endif
91
92 TEST_START("load data");
93 msg = load_file("namespace");
94 namespace = sshbuf_dup_string(msg);
95 ASSERT_PTR_NE(namespace, NULL);
96 sshbuf_free(msg);
97 msg = load_file("signed-data");
98 TEST_DONE();
99
100#ifdef WITH_OPENSSL
101 TEST_START("check RSA signature");
102 check_sig("rsa.pub", "rsa.sig", msg, namespace);
103 TEST_DONE();
104
105 TEST_START("check DSA signature");
106 check_sig("dsa.pub", "dsa.sig", msg, namespace);
107 TEST_DONE();
108
109#ifdef OPENSSL_HAS_ECC
110 TEST_START("check ECDSA signature");
111 check_sig("ecdsa.pub", "ecdsa.sig", msg, namespace);
112 TEST_DONE();
113#endif
114#endif
115
116 TEST_START("check ED25519 signature");
117 check_sig("ed25519.pub", "ed25519.sig", msg, namespace);
118 TEST_DONE();
119
120#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
121 TEST_START("check ECDSA-SK signature");
122 check_sig("ecdsa_sk.pub", "ecdsa_sk.sig", msg, namespace);
123 TEST_DONE();
124#endif
125
126 TEST_START("check ED25519-SK signature");
127 check_sig("ed25519_sk.pub", "ed25519_sk.sig", msg, namespace);
128 TEST_DONE();
129
130#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
131 TEST_START("check ECDSA-SK webauthn signature");
132 check_sig("ecdsa_sk_webauthn.pub", "ecdsa_sk_webauthn.sig",
133 msg, namespace);
134 TEST_DONE();
135#endif
136
137 sshbuf_free(msg);
138 free(namespace);
139}
diff --git a/regress/unittests/sshsig/webauthn.html b/regress/unittests/sshsig/webauthn.html
new file mode 100644
index 000000000..953041e61
--- /dev/null
+++ b/regress/unittests/sshsig/webauthn.html
@@ -0,0 +1,692 @@
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
4<title>webauthn test</title>
5</head>
6<body onload="init()">
7<h1>webauthn test</h1>
8<p>
9This is a demo/test page for generating FIDO keys and signatures in SSH
10formats. The page initially displays a form to generate a FIDO key and
11convert it to a SSH public key.
12</p>
13<p>
14Once a key has been generated, an additional form will be displayed to
15allow signing of data using the just-generated key. The data may be signed
16as either a raw SSH signature or wrapped in a sshsig message (the latter is
17easier to test using command-line tools.
18</p>
19<p>
20Lots of debugging is printed along the way.
21</p>
22<h2>Enroll</h2>
23<span id="error" style="color: #800; font-weight: bold; font-size: 150%;"></span>
24<form id="enrollform">
25<table>
26<tr>
27<td><b>Username:</b></td>
28<td><input id="username" type="text" size="20" name="user" value="test" /></td>
29</tr>
30<tr><td></td><td><input id="assertsubmit" type="submit" value="submit" /></td></tr>
31</table>
32</form>
33<span id="enrollresult" style="visibility: hidden;">
34<h2>clientData</h2>
35<pre id="enrollresultjson" style="color: #008; font-family: monospace;"></pre>
36<h2>attestationObject raw</h2>
37<pre id="enrollresultraw" style="color: #008; font-family: monospace;"></pre>
38<h2>attestationObject</h2>
39<pre id="enrollresultattestobj" style="color: #008; font-family: monospace;"></pre>
40<h2>authData raw</h2>
41<pre id="enrollresultauthdataraw" style="color: #008; font-family: monospace;"></pre>
42<h2>authData</h2>
43<pre id="enrollresultauthdata" style="color: #008; font-family: monospace;"></pre>
44<h2>SSH pubkey blob</h2>
45<pre id="enrollresultpkblob" style="color: #008; font-family: monospace;"></pre>
46<h2>SSH pubkey string</h2>
47<pre id="enrollresultpk" style="color: #008; font-family: monospace;"></pre>
48</span>
49<span id="assertsection" style="visibility: hidden;">
50<h2>Assert</h2>
51<form id="assertform">
52<span id="asserterror" style="color: #800; font-weight: bold;"></span>
53<table>
54<tr>
55<td><b>Data to sign:</b></td>
56<td><input id="message" type="text" size="20" name="message" value="test" /></td>
57</tr>
58<tr>
59<td><input id="message_sshsig" type="checkbox" checked /> use sshsig format</td>
60</tr>
61<tr>
62<td><b>Signature namespace:</b></td>
63<td><input id="message_namespace" type="text" size="20" name="namespace" value="test" /></td>
64</tr>
65<tr><td></td><td><input type="submit" value="submit" /></td></tr>
66</table>
67</form>
68</span>
69<span id="assertresult" style="visibility: hidden;">
70<h2>clientData</h2>
71<pre id="assertresultjson" style="color: #008; font-family: monospace;"></pre>
72<h2>signature raw</h2>
73<pre id="assertresultsigraw" style="color: #008; font-family: monospace;"></pre>
74<h2>authenticatorData raw</h2>
75<pre id="assertresultauthdataraw" style="color: #008; font-family: monospace;"></pre>
76<h2>authenticatorData</h2>
77<pre id="assertresultauthdata" style="color: #008; font-family: monospace;"></pre>
78<h2>signature in SSH format</h2>
79<pre id="assertresultsshsigraw" style="color: #008; font-family: monospace;"></pre>
80<h2>signature in SSH format (base64 encoded)</h2>
81<pre id="assertresultsshsigb64" style="color: #008; font-family: monospace;"></pre>
82</span>
83</body>
84<script>
85// ------------------------------------------------------------------
86// a crappy CBOR decoder - 20200401 djm@openbsd.org
87
88var CBORDecode = function(buffer) {
89 this.buf = buffer
90 this.v = new DataView(buffer)
91 this.offset = 0
92}
93
94CBORDecode.prototype.empty = function() {
95 return this.offset >= this.buf.byteLength
96}
97
98CBORDecode.prototype.getU8 = function() {
99 let r = this.v.getUint8(this.offset)
100 this.offset += 1
101 return r
102}
103
104CBORDecode.prototype.getU16 = function() {
105 let r = this.v.getUint16(this.offset)
106 this.offset += 2
107 return r
108}
109
110CBORDecode.prototype.getU32 = function() {
111 let r = this.v.getUint32(this.offset)
112 this.offset += 4
113 return r
114}
115
116CBORDecode.prototype.getU64 = function() {
117 let r = this.v.getUint64(this.offset)
118 this.offset += 8
119 return r
120}
121
122CBORDecode.prototype.getCBORTypeLen = function() {
123 let tl, t, l
124 tl = this.getU8()
125 t = (tl & 0xe0) >> 5
126 l = tl & 0x1f
127 return [t, this.decodeInteger(l)]
128}
129
130CBORDecode.prototype.decodeInteger = function(len) {
131 switch (len) {
132 case 0x18: return this.getU8()
133 case 0x19: return this.getU16()
134 case 0x20: return this.getU32()
135 case 0x21: return this.getU64()
136 default:
137 if (len <= 23) {
138 return len
139 }
140 throw new Error("Unsupported int type 0x" + len.toString(16))
141 }
142}
143
144CBORDecode.prototype.decodeNegint = function(len) {
145 let r = -(this.decodeInteger(len) + 1)
146 return r
147}
148
149CBORDecode.prototype.decodeByteString = function(len) {
150 let r = this.buf.slice(this.offset, this.offset + len)
151 this.offset += len
152 return r
153}
154
155CBORDecode.prototype.decodeTextString = function(len) {
156 let u8dec = new TextDecoder('utf-8')
157 r = u8dec.decode(this.decodeByteString(len))
158 return r
159}
160
161CBORDecode.prototype.decodeArray = function(len, level) {
162 let r = []
163 for (let i = 0; i < len; i++) {
164 let v = this.decodeInternal(level)
165 r.push(v)
166 // console.log("decodeArray level " + level.toString() + " index " + i.toString() + " value " + JSON.stringify(v))
167 }
168 return r
169}
170
171CBORDecode.prototype.decodeMap = function(len, level) {
172 let r = {}
173 for (let i = 0; i < len; i++) {
174 let k = this.decodeInternal(level)
175 let v = this.decodeInternal(level)
176 r[k] = v
177 // console.log("decodeMap level " + level.toString() + " key " + k.toString() + " value " + JSON.stringify(v))
178 // XXX check string keys, duplicates
179 }
180 return r
181}
182
183CBORDecode.prototype.decodePrimitive = function(t) {
184 switch (t) {
185 case 20: return false
186 case 21: return true
187 case 22: return null
188 case 23: return undefined
189 default:
190 throw new Error("Unsupported primitive 0x" + t.toString(2))
191 }
192}
193
194CBORDecode.prototype.decodeInternal = function(level) {
195 if (level > 256) {
196 throw new Error("CBOR nesting too deep")
197 }
198 let t, l, r
199 [t, l] = this.getCBORTypeLen()
200 // console.log("decode level " + level.toString() + " type " + t.toString() + " len " + l.toString())
201 switch (t) {
202 case 0:
203 r = this.decodeInteger(l)
204 break
205 case 1:
206 r = this.decodeNegint(l)
207 break
208 case 2:
209 r = this.decodeByteString(l)
210 break
211 case 3:
212 r = this.decodeTextString(l)
213 break
214 case 4:
215 r = this.decodeArray(l, level + 1)
216 break
217 case 5:
218 r = this.decodeMap(l, level + 1)
219 break
220 case 6:
221 console.log("XXX ignored semantic tag " + this.decodeInteger(l).toString())
222 break;
223 case 7:
224 r = this.decodePrimitive(l)
225 break
226 default:
227 throw new Error("Unsupported type 0x" + t.toString(2) + " len " + l.toString())
228 }
229 // console.log("decode level " + level.toString() + " value " + JSON.stringify(r))
230 return r
231}
232
233CBORDecode.prototype.decode = function() {
234 return this.decodeInternal(0)
235}
236
237// ------------------------------------------------------------------
238// a crappy SSH message packer - 20200401 djm@openbsd.org
239
240var SSHMSG = function() {
241 this.r = []
242}
243
244SSHMSG.prototype.serialise = function() {
245 let len = 0
246 for (buf of this.r) {
247 len += buf.length
248 }
249 let r = new ArrayBuffer(len)
250 let v = new Uint8Array(r)
251 let offset = 0
252 for (buf of this.r) {
253 v.set(buf, offset)
254 offset += buf.length
255 }
256 if (offset != r.byteLength) {
257 throw new Error("djm can't count")
258 }
259 return r
260}
261
262SSHMSG.prototype.serialiseBase64 = function(v) {
263 let b = this.serialise()
264 return btoa(String.fromCharCode(...new Uint8Array(b)));
265}
266
267SSHMSG.prototype.putU8 = function(v) {
268 this.r.push(new Uint8Array([v]))
269}
270
271SSHMSG.prototype.putU32 = function(v) {
272 this.r.push(new Uint8Array([
273 (v >> 24) & 0xff,
274 (v >> 16) & 0xff,
275 (v >> 8) & 0xff,
276 (v & 0xff)
277 ]))
278}
279
280SSHMSG.prototype.put = function(v) {
281 this.r.push(new Uint8Array(v))
282}
283
284SSHMSG.prototype.putString = function(v) {
285 let enc = new TextEncoder();
286 let venc = enc.encode(v)
287 this.putU32(venc.length)
288 this.put(venc)
289}
290
291SSHMSG.prototype.putSSHMSG = function(v) {
292 let msg = v.serialise()
293 this.putU32(msg.byteLength)
294 this.put(msg)
295}
296
297SSHMSG.prototype.putBytes = function(v) {
298 this.putU32(v.byteLength)
299 this.put(v)
300}
301
302SSHMSG.prototype.putECPoint = function(x, y) {
303 let x8 = new Uint8Array(x)
304 let y8 = new Uint8Array(y)
305 this.putU32(1 + x8.length + y8.length)
306 this.putU8(0x04) // Uncompressed point format.
307 this.put(x8)
308 this.put(y8)
309}
310
311// ------------------------------------------------------------------
312// webauthn to SSH glue - djm@openbsd.org 20200408
313
314function error(msg, ...args) {
315 document.getElementById("error").innerText = msg
316 console.log(msg)
317 for (const arg of args) {
318 console.dir(arg)
319 }
320}
321function hexdump(buf) {
322 const hex = Array.from(new Uint8Array(buf)).map(
323 b => b.toString(16).padStart(2, "0"))
324 const fmt = new Array()
325 for (let i = 0; i < hex.length; i++) {
326 if ((i % 16) == 0) {
327 // Prepend length every 16 bytes.
328 fmt.push(i.toString(16).padStart(4, "0"))
329 fmt.push(" ")
330 }
331 fmt.push(hex[i])
332 fmt.push(" ")
333 if ((i % 16) == 15) {
334 fmt.push("\n")
335 }
336 }
337 return fmt.join("")
338}
339function enrollform_submit(event) {
340 event.preventDefault();
341 console.log("submitted")
342 username = event.target.elements.username.value
343 if (username === "") {
344 error("no username specified")
345 return false
346 }
347 enrollStart(username)
348}
349function enrollStart(username) {
350 let challenge = new Uint8Array(32)
351 window.crypto.getRandomValues(challenge)
352 let userid = new Uint8Array(8)
353 window.crypto.getRandomValues(userid)
354
355 console.log("challenge:" + btoa(challenge))
356 console.log("userid:" + btoa(userid))
357
358 let pkopts = {
359 challenge: challenge,
360 rp: {
361 name: "mindrot.org",
362 id: "mindrot.org",
363 },
364 user: {
365 id: userid,
366 name: username,
367 displayName: username,
368 },
369 authenticatorSelection: {
370 authenticatorAttachment: "cross-platform",
371 userVerification: "discouraged",
372 },
373 pubKeyCredParams: [{alg: -7, type: "public-key"}], // ES256
374 timeout: 30 * 1000,
375 };
376 console.dir(pkopts)
377 window.enrollOpts = pkopts
378 let credpromise = navigator.credentials.create({ publicKey: pkopts });
379 credpromise.then(enrollSuccess, enrollFailure)
380}
381function enrollFailure(result) {
382 error("Enroll failed", result)
383}
384function enrollSuccess(result) {
385 console.log("Enroll succeeded")
386 console.dir(result)
387 window.enrollResult = result
388 document.getElementById("enrollresult").style.visibility = "visible"
389
390 // Show the clientData
391 let u8dec = new TextDecoder('utf-8')
392 clientData = u8dec.decode(result.response.clientDataJSON)
393 document.getElementById("enrollresultjson").innerText = clientData
394
395 // Decode and show the attestationObject
396 document.getElementById("enrollresultraw").innerText = hexdump(result.response.attestationObject)
397 let aod = new CBORDecode(result.response.attestationObject)
398 let attestationObject = aod.decode()
399 console.log("attestationObject")
400 console.dir(attestationObject)
401 document.getElementById("enrollresultattestobj").innerText = JSON.stringify(attestationObject)
402
403 // Decode and show the authData
404 document.getElementById("enrollresultauthdataraw").innerText = hexdump(attestationObject.authData)
405 let authData = decodeAuthenticatorData(attestationObject.authData, true)
406 console.log("authData")
407 console.dir(authData)
408 window.enrollAuthData = authData
409 document.getElementById("enrollresultauthdata").innerText = JSON.stringify(authData)
410
411 // Reformat the pubkey as a SSH key for easy verification
412 window.rawKey = reformatPubkey(authData.attestedCredentialData.credentialPublicKey, window.enrollOpts.rp.id)
413 console.log("SSH pubkey blob")
414 console.dir(window.rawKey)
415 document.getElementById("enrollresultpkblob").innerText = hexdump(window.rawKey)
416 let pk64 = btoa(String.fromCharCode(...new Uint8Array(window.rawKey)));
417 let pk = "sk-ecdsa-sha2-nistp256@openssh.com " + pk64
418 document.getElementById("enrollresultpk").innerText = pk
419
420 // Success: show the assertion form.
421 document.getElementById("assertsection").style.visibility = "visible"
422}
423
424function decodeAuthenticatorData(authData, expectCred) {
425 let r = new Object()
426 let v = new DataView(authData)
427
428 r.rpIdHash = authData.slice(0, 32)
429 r.flags = v.getUint8(32)
430 r.signCount = v.getUint32(33)
431
432 // Decode attestedCredentialData if present.
433 let offset = 37
434 let acd = new Object()
435 if (expectCred) {
436 acd.aaguid = authData.slice(offset, offset+16)
437 offset += 16
438 let credentialIdLength = v.getUint16(offset)
439 offset += 2
440 acd.credentialIdLength = credentialIdLength
441 acd.credentialId = authData.slice(offset, offset+credentialIdLength)
442 offset += credentialIdLength
443 r.attestedCredentialData = acd
444 }
445 console.log("XXXXX " + offset.toString())
446 let pubkeyrest = authData.slice(offset, authData.byteLength)
447 let pkdecode = new CBORDecode(pubkeyrest)
448 if (expectCred) {
449 // XXX unsafe: doesn't mandate COSE canonical format.
450 acd.credentialPublicKey = pkdecode.decode()
451 }
452 if (!pkdecode.empty()) {
453 // Decode extensions if present.
454 r.extensions = pkdecode.decode()
455 }
456 return r
457}
458
459function reformatPubkey(pk, rpid) {
460 // pk is in COSE format. We only care about a tiny subset.
461 if (pk[1] != 2) {
462 console.dir(pk)
463 throw new Error("pubkey is not EC")
464 }
465 if (pk[-1] != 1) {
466 throw new Error("pubkey is not in P256")
467 }
468 if (pk[3] != -7) {
469 throw new Error("pubkey is not ES256")
470 }
471 if (pk[-2].byteLength != 32 || pk[-3].byteLength != 32) {
472 throw new Error("pubkey EC coords have bad length")
473 }
474 let msg = new SSHMSG()
475 msg.putString("sk-ecdsa-sha2-nistp256@openssh.com") // Key type
476 msg.putString("nistp256") // Key curve
477 msg.putECPoint(pk[-2], pk[-3]) // EC key
478 msg.putString(rpid) // RP ID
479 return msg.serialise()
480}
481
482async function assertform_submit(event) {
483 event.preventDefault();
484 console.log("submitted")
485 message = event.target.elements.message.value
486 if (message === "") {
487 error("no message specified")
488 return false
489 }
490 let enc = new TextEncoder()
491 let encmsg = enc.encode(message)
492 window.assertSignRaw = !event.target.elements.message_sshsig.checked
493 console.log("using sshsig ", !window.assertSignRaw)
494 if (window.assertSignRaw) {
495 assertStart(encmsg)
496 return
497 }
498 // Format a sshsig-style message.
499 window.sigHashAlg = "sha512"
500 let msghash = await crypto.subtle.digest("SHA-512", encmsg);
501 console.log("raw message hash")
502 console.dir(msghash)
503 window.sigNamespace = event.target.elements.message_namespace.value
504 let sigbuf = new SSHMSG()
505 sigbuf.put(enc.encode("SSHSIG"))
506 sigbuf.putString(window.sigNamespace)
507 sigbuf.putU32(0) // Reserved string
508 sigbuf.putString(window.sigHashAlg)
509 sigbuf.putBytes(msghash)
510 let msg = sigbuf.serialise()
511 console.log("sigbuf")
512 console.dir(msg)
513 assertStart(msg)
514}
515
516function assertStart(message) {
517 let assertReqOpts = {
518 challenge: message,
519 rpId: "mindrot.org",
520 allowCredentials: [{
521 type: 'public-key',
522 id: window.enrollResult.rawId,
523 }],
524 userVerification: "discouraged",
525 timeout: (30 * 1000),
526 }
527 console.log("assertReqOpts")
528 console.dir(assertReqOpts)
529 window.assertReqOpts = assertReqOpts
530 let assertpromise = navigator.credentials.get({
531 publicKey: assertReqOpts
532 });
533 assertpromise.then(assertSuccess, assertFailure)
534}
535function assertFailure(result) {
536 error("Assertion failed", result)
537}
538function linewrap(s) {
539 const linelen = 70
540 let ret = ""
541 for (let i = 0; i < s.length; i += linelen) {
542 end = i + linelen
543 if (end > s.length) {
544 end = s.length
545 }
546 if (i > 0) {
547 ret += "\n"
548 }
549 ret += s.slice(i, end)
550 }
551 return ret + "\n"
552}
553function assertSuccess(result) {
554 console.log("Assertion succeeded")
555 console.dir(result)
556 window.assertResult = result
557 document.getElementById("assertresult").style.visibility = "visible"
558
559 // show the clientData.
560 let u8dec = new TextDecoder('utf-8')
561 clientData = u8dec.decode(result.response.clientDataJSON)
562 document.getElementById("assertresultjson").innerText = clientData
563
564 // show the signature.
565 document.getElementById("assertresultsigraw").innerText = hexdump(result.response.signature)
566
567 // decode and show the authData.
568 document.getElementById("assertresultauthdataraw").innerText = hexdump(result.response.authenticatorData)
569 authData = decodeAuthenticatorData(result.response.authenticatorData, false)
570 document.getElementById("assertresultauthdata").innerText = JSON.stringify(authData)
571
572 // Parse and reformat the signature to an SSH style signature.
573 let sshsig = reformatSignature(result.response.signature, clientData, authData)
574 document.getElementById("assertresultsshsigraw").innerText = hexdump(sshsig)
575 let sig64 = btoa(String.fromCharCode(...new Uint8Array(sshsig)));
576 if (window.assertSignRaw) {
577 document.getElementById("assertresultsshsigb64").innerText = sig64
578 } else {
579 document.getElementById("assertresultsshsigb64").innerText =
580 "-----BEGIN SSH SIGNATURE-----\n" + linewrap(sig64) +
581 "-----END SSH SIGNATURE-----\n";
582 }
583}
584
585function reformatSignature(sig, clientData, authData) {
586 if (sig.byteLength < 2) {
587 throw new Error("signature is too short")
588 }
589 let offset = 0
590 let v = new DataView(sig)
591 // Expect an ASN.1 SEQUENCE that exactly spans the signature.
592 if (v.getUint8(offset) != 0x30) {
593 throw new Error("signature not an ASN.1 sequence")
594 }
595 offset++
596 let seqlen = v.getUint8(offset)
597 offset++
598 if ((seqlen & 0x80) != 0 || seqlen != sig.byteLength - offset) {
599 throw new Error("signature has unexpected length " + seqlen.toString() + " vs expected " + (sig.byteLength - offset).toString())
600 }
601
602 // Parse 'r' INTEGER value.
603 if (v.getUint8(offset) != 0x02) {
604 throw new Error("signature r not an ASN.1 integer")
605 }
606 offset++
607 let rlen = v.getUint8(offset)
608 offset++
609 if ((rlen & 0x80) != 0 || rlen > sig.byteLength - offset) {
610 throw new Error("signature r has unexpected length " + rlen.toString() + " vs buffer " + (sig.byteLength - offset).toString())
611 }
612 let r = sig.slice(offset, offset + rlen)
613 offset += rlen
614 console.log("sig_r")
615 console.dir(r)
616
617 // Parse 's' INTEGER value.
618 if (v.getUint8(offset) != 0x02) {
619 throw new Error("signature r not an ASN.1 integer")
620 }
621 offset++
622 let slen = v.getUint8(offset)
623 offset++
624 if ((slen & 0x80) != 0 || slen > sig.byteLength - offset) {
625 throw new Error("signature s has unexpected length " + slen.toString() + " vs buffer " + (sig.byteLength - offset).toString())
626 }
627 let s = sig.slice(offset, offset + slen)
628 console.log("sig_s")
629 console.dir(s)
630 offset += slen
631
632 if (offset != sig.byteLength) {
633 throw new Error("unexpected final offset during signature parsing " + offset.toString() + " expected " + sig.byteLength.toString())
634 }
635
636 // Reformat as an SSH signature.
637 let clientDataParsed = JSON.parse(clientData)
638 let innersig = new SSHMSG()
639 innersig.putBytes(r)
640 innersig.putBytes(s)
641
642 let rawsshsig = new SSHMSG()
643 rawsshsig.putString("webauthn-sk-ecdsa-sha2-nistp256@openssh.com")
644 rawsshsig.putSSHMSG(innersig)
645 rawsshsig.putU8(authData.flags)
646 rawsshsig.putU32(authData.signCount)
647 rawsshsig.putString(clientDataParsed.origin)
648 rawsshsig.putString(clientData)
649 if (authData.extensions == undefined) {
650 rawsshsig.putU32(0)
651 } else {
652 rawsshsig.putBytes(authData.extensions)
653 }
654
655 if (window.assertSignRaw) {
656 return rawsshsig.serialise()
657 }
658 // Format as SSHSIG.
659 let enc = new TextEncoder()
660 let sshsig = new SSHMSG()
661 sshsig.put(enc.encode("SSHSIG"))
662 sshsig.putU32(0x01) // Signature version.
663 sshsig.putBytes(window.rawKey)
664 sshsig.putString(window.sigNamespace)
665 sshsig.putU32(0) // Reserved string
666 sshsig.putString(window.sigHashAlg)
667 sshsig.putBytes(rawsshsig.serialise())
668 return sshsig.serialise()
669}
670
671function toggleNamespaceVisibility() {
672 const assertsigtype = document.getElementById('message_sshsig');
673 const assertsignamespace = document.getElementById('message_namespace');
674 assertsignamespace.disabled = !assertsigtype.checked;
675}
676
677function init() {
678 if (document.location.protocol != "https:") {
679 error("This page must be loaded via https")
680 const assertsubmit = document.getElementById('assertsubmit')
681 assertsubmit.disabled = true
682 }
683 const enrollform = document.getElementById('enrollform');
684 enrollform.addEventListener('submit', enrollform_submit);
685 const assertform = document.getElementById('assertform');
686 assertform.addEventListener('submit', assertform_submit);
687 const assertsigtype = document.getElementById('message_sshsig');
688 assertsigtype.onclick = toggleNamespaceVisibility;
689}
690</script>
691
692</html>