1*bb23672eSdjm#	$OpenBSD: agent-pkcs11-restrict.sh,v 1.1 2023/12/18 14:49:39 djm Exp $
2*bb23672eSdjm#	Placed in the Public Domain.
3*bb23672eSdjm
4*bb23672eSdjmtid="pkcs11 agent constraint test"
5*bb23672eSdjm
6*bb23672eSdjmp11_setup || skip "No PKCS#11 library found"
7*bb23672eSdjm
8*bb23672eSdjmrm -f $SSH_AUTH_SOCK $OBJ/agent.log $OBJ/host_[abcx]* $OBJ/user_[abcx]*
9*bb23672eSdjmrm -f $OBJ/sshd_proxy_host* $OBJ/ssh_output* $OBJ/expect_*
10*bb23672eSdjmrm -f $OBJ/ssh_proxy[._]* $OBJ/command $OBJ/authorized_keys_*
11*bb23672eSdjm
12*bb23672eSdjmtrace "generate host keys"
13*bb23672eSdjmfor h in a b x ca ; do
14*bb23672eSdjm	$SSHKEYGEN -q -t ed25519 -C host_$h -N '' -f $OBJ/host_$h || \
15*bb23672eSdjm		fatal "ssh-keygen hostkey failed"
16*bb23672eSdjmdone
17*bb23672eSdjm
18*bb23672eSdjm# XXX test CA hostcerts too.
19*bb23672eSdjm
20*bb23672eSdjmkey_for() {
21*bb23672eSdjm	case $h in
22*bb23672eSdjm	a) K="${SSH_SOFTHSM_DIR}/RSA.pub" ;;
23*bb23672eSdjm	b) K="${SSH_SOFTHSM_DIR}/EC.pub" ;;
24*bb23672eSdjm	*) K="" ;;
25*bb23672eSdjm	esac
26*bb23672eSdjm	export K
27*bb23672eSdjm}
28*bb23672eSdjm
29*bb23672eSdjmSSH_AUTH_SOCK="$OBJ/agent.sock"
30*bb23672eSdjmexport SSH_AUTH_SOCK
31*bb23672eSdjmrm -f $SSH_AUTH_SOCK
32*bb23672eSdjmtrace "start agent"
33*bb23672eSdjm${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK > $OBJ/agent.log 2>&1 &
34*bb23672eSdjmAGENT_PID=$!
35*bb23672eSdjmtrap "kill $AGENT_PID" EXIT
36*bb23672eSdjmfor x in 0 1 2 3 4 ; do
37*bb23672eSdjm	# Give it a chance to start
38*bb23672eSdjm	${SSHADD} -l > /dev/null 2>&1
39*bb23672eSdjm	r=$?
40*bb23672eSdjm	test $r -eq 1 && break
41*bb23672eSdjm	sleep 1
42*bb23672eSdjmdone
43*bb23672eSdjmif [ $r -ne 1 ]; then
44*bb23672eSdjm	fatal "ssh-add -l did not fail with exit code 1 (got $r)"
45*bb23672eSdjmfi
46*bb23672eSdjm
47*bb23672eSdjm# XXX a lot of this is a copy of agent-restrict.sh, but I couldn't see a nice
48*bb23672eSdjm# way to factor it out -djm
49*bb23672eSdjm
50*bb23672eSdjmtrace "prepare client config"
51*bb23672eSdjmegrep -vi '(identityfile|hostname|hostkeyalias|proxycommand)' \
52*bb23672eSdjm	$OBJ/ssh_proxy > $OBJ/ssh_proxy.bak
53*bb23672eSdjmcat << _EOF > $OBJ/ssh_proxy
54*bb23672eSdjmIdentitiesOnly yes
55*bb23672eSdjmForwardAgent yes
56*bb23672eSdjmExitOnForwardFailure yes
57*bb23672eSdjm_EOF
58*bb23672eSdjmcp $OBJ/ssh_proxy $OBJ/ssh_proxy_noid
59*bb23672eSdjmfor h in a b ; do
60*bb23672eSdjm	key_for $h
61*bb23672eSdjm	cat << _EOF >> $OBJ/ssh_proxy
62*bb23672eSdjmHost host_$h
63*bb23672eSdjm	Hostname host_$h
64*bb23672eSdjm	HostkeyAlias host_$h
65*bb23672eSdjm	IdentityFile $K
66*bb23672eSdjm	ProxyCommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" ${OBJ}/sshd-log-wrapper.sh -i -f $OBJ/sshd_proxy_host_$h
67*bb23672eSdjm_EOF
68*bb23672eSdjm	# Variant with no specified keys.
69*bb23672eSdjm	cat << _EOF >> $OBJ/ssh_proxy_noid
70*bb23672eSdjmHost host_$h
71*bb23672eSdjm	Hostname host_$h
72*bb23672eSdjm	HostkeyAlias host_$h
73*bb23672eSdjm	ProxyCommand ${SUDO} env SSH_SK_HELPER=\"$SSH_SK_HELPER\" ${OBJ}/sshd-log-wrapper.sh -i -f $OBJ/sshd_proxy_host_$h
74*bb23672eSdjm_EOF
75*bb23672eSdjmdone
76*bb23672eSdjmcat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy
77*bb23672eSdjmcat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy_noid
78*bb23672eSdjm
79*bb23672eSdjmLC_ALL=C
80*bb23672eSdjmexport LC_ALL
81*bb23672eSdjmecho "SetEnv LC_ALL=${LC_ALL}" >> sshd_proxy
82*bb23672eSdjm
83*bb23672eSdjmtrace "prepare known_hosts"
84*bb23672eSdjmrm -f $OBJ/known_hosts
85*bb23672eSdjmfor h in a b x ; do
86*bb23672eSdjm	(printf "host_$h " ; cat $OBJ/host_${h}.pub) >> $OBJ/known_hosts
87*bb23672eSdjmdone
88*bb23672eSdjm
89*bb23672eSdjmtrace "prepare server configs"
90*bb23672eSdjmegrep -vi '(hostkey|pidfile)' $OBJ/sshd_proxy \
91*bb23672eSdjm	> $OBJ/sshd_proxy.bak
92*bb23672eSdjmfor h in a b ; do
93*bb23672eSdjm	cp $OBJ/sshd_proxy.bak $OBJ/sshd_proxy_host_$h
94*bb23672eSdjm	cat << _EOF >> $OBJ/sshd_proxy_host_$h
95*bb23672eSdjmExposeAuthInfo yes
96*bb23672eSdjmHostkey $OBJ/host_$h
97*bb23672eSdjm_EOF
98*bb23672eSdjm	cp $OBJ/sshd_proxy_host_$h $OBJ/sshd_proxy_host_${h}.bak
99*bb23672eSdjmdone
100*bb23672eSdjm
101*bb23672eSdjmtrace "prepare authorized_keys"
102*bb23672eSdjmcat >> $OBJ/command << EOF
103*bb23672eSdjm#!/bin/sh
104*bb23672eSdjmecho USERAUTH
105*bb23672eSdjmcat \$SSH_USER_AUTH
106*bb23672eSdjmecho AGENT
107*bb23672eSdjmif $SSHADD -ql >/dev/null 2>&1 ; then
108*bb23672eSdjm	$SSHADD -L | cut -d' ' -f1-2 | sort
109*bb23672eSdjmelse
110*bb23672eSdjm	echo NONE
111*bb23672eSdjmfi
112*bb23672eSdjmEOF
113*bb23672eSdjmchmod a+x $OBJ/command
114*bb23672eSdjm>$OBJ/authorized_keys_$USER
115*bb23672eSdjmfor h in a b ; do
116*bb23672eSdjm	key_for $h
117*bb23672eSdjm	(printf "%s" "restrict,agent-forwarding,command=\"$OBJ/command\" ";
118*bb23672eSdjm	 cat $K) >> $OBJ/authorized_keys_$USER
119*bb23672eSdjmdone
120*bb23672eSdjm
121*bb23672eSdjmtrace "unrestricted keys"
122*bb23672eSdjm$SSHADD -qD >/dev/null || fatal "clear agent failed"
123*bb23672eSdjmp11_ssh_add -qs ${TEST_SSH_PKCS11} ||
124*bb23672eSdjm	fatal "failed to add keys"
125*bb23672eSdjmfor h in a b ; do
126*bb23672eSdjm	key_for $h
127*bb23672eSdjm	echo USERAUTH > $OBJ/expect_$h
128*bb23672eSdjm	printf "publickey " >> $OBJ/expect_$h
129*bb23672eSdjm	cat $K >> $OBJ/expect_$h
130*bb23672eSdjm	echo AGENT >> $OBJ/expect_$h
131*bb23672eSdjm	$SSHADD -L | cut -d' ' -f1-2 | sort >> $OBJ/expect_$h
132*bb23672eSdjm	${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
133*bb23672eSdjm	    host_$h true > $OBJ/ssh_output || fatal "test ssh $h failed"
134*bb23672eSdjm	cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output"
135*bb23672eSdjmdone
136*bb23672eSdjm
137*bb23672eSdjmtrace "restricted to different host"
138*bb23672eSdjm$SSHADD -qD >/dev/null || fatal "clear agent failed"
139*bb23672eSdjmp11_ssh_add -q -h host_x -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts ||
140*bb23672eSdjm	fatal "failed to add keys"
141*bb23672eSdjmfor h in a b ; do
142*bb23672eSdjm	key_for $h
143*bb23672eSdjm	${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
144*bb23672eSdjm	    host_$h true > $OBJ/ssh_output && fatal "test ssh $h succeeded"
145*bb23672eSdjmdone
146*bb23672eSdjm
147*bb23672eSdjmtrace "restricted to destination host"
148*bb23672eSdjm$SSHADD -qD >/dev/null || fatal "clear agent failed"
149*bb23672eSdjmp11_ssh_add -q -h host_a -h host_b -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts ||
150*bb23672eSdjm	fatal "failed to add keys"
151*bb23672eSdjmfor h in a b ; do
152*bb23672eSdjm	key_for $h
153*bb23672eSdjm	echo USERAUTH > $OBJ/expect_$h
154*bb23672eSdjm	printf "publickey " >> $OBJ/expect_$h
155*bb23672eSdjm	cat $K >> $OBJ/expect_$h
156*bb23672eSdjm	echo AGENT >> $OBJ/expect_$h
157*bb23672eSdjm	echo NONE >> $OBJ/expect_$h
158*bb23672eSdjm	${SSH} -F $OBJ/ssh_proxy -oIdentityFile=$K \
159*bb23672eSdjm	    host_$h true > $OBJ/ssh_output || fatal "test ssh $h failed"
160*bb23672eSdjm	cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output"
161*bb23672eSdjmdone
162*bb23672eSdjm
163*bb23672eSdjmtrace "restricted multihop"
164*bb23672eSdjm$SSHADD -qD >/dev/null || fatal "clear agent failed"
165*bb23672eSdjmp11_ssh_add -q -h host_a -h "host_a>host_b" \
166*bb23672eSdjm    -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts || fatal "failed to add keys"
167*bb23672eSdjmkey_for a
168*bb23672eSdjmAK=$K
169*bb23672eSdjmkey_for b
170*bb23672eSdjmBK=$K
171*bb23672eSdjm# Prepare authorized_keys file to additionally ssh to host_b
172*bb23672eSdjm_command="echo LOCAL ; ${OBJ}/command ; echo REMOTE; ${SSH} -AF $OBJ/ssh_proxy -oIdentityFile=$BK host_b"
173*bb23672eSdjm(printf "%s" "restrict,agent-forwarding,command=\"$_command\" ";
174*bb23672eSdjm cat $BK) > $OBJ/authorized_keys_a
175*bb23672eSdjmgrep -vi AuthorizedKeysFile $OBJ/sshd_proxy_host_a.bak > $OBJ/sshd_proxy_host_a
176*bb23672eSdjmecho "AuthorizedKeysFile $OBJ/authorized_keys_a" >> $OBJ/sshd_proxy_host_a
177*bb23672eSdjm# Prepare expected output from both hosts.
178*bb23672eSdjmecho LOCAL > $OBJ/expect_a
179*bb23672eSdjmecho USERAUTH >> $OBJ/expect_a
180*bb23672eSdjmprintf "publickey " >> $OBJ/expect_a
181*bb23672eSdjmcat $AK >> $OBJ/expect_a
182*bb23672eSdjmecho AGENT >> $OBJ/expect_a
183*bb23672eSdjm$SSHADD -L | cut -d' ' -f1-2 | sort >> $OBJ/expect_a
184*bb23672eSdjmecho REMOTE >> $OBJ/expect_a
185*bb23672eSdjmecho USERAUTH >> $OBJ/expect_a
186*bb23672eSdjmprintf "publickey " >> $OBJ/expect_a
187*bb23672eSdjmcat $BK >> $OBJ/expect_a
188*bb23672eSdjmecho AGENT >> $OBJ/expect_a
189*bb23672eSdjmecho NONE >> $OBJ/expect_a
190*bb23672eSdjm${SSH} -AF $OBJ/ssh_proxy -oIdentityFile=$AK \
191*bb23672eSdjm    host_a whatever > $OBJ/ssh_output || fatal "test ssh $h failed"
192*bb23672eSdjmcmp $OBJ/expect_a $OBJ/ssh_output || fatal "unexpected output"
193*bb23672eSdjm
194