1295367Sdes#	$OpenBSD: cert-hostkey.sh,v 1.13 2015/07/10 06:23:25 markus Exp $
2204861Sdes#	Placed in the Public Domain.
3204861Sdes
4204861Sdestid="certified host keys"
5204861Sdes
6295367Sdesrm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/host_revoked_*
7295367Sdesrm -f $OBJ/cert_host_key* $OBJ/host_krl_*
8295367Sdes
9295367Sdes# Allow all hostkey/pubkey types, prefer certs for the client
10295367Sdestypes=""
11295367Sdesfor i in `$SSH -Q key`; do
12295367Sdes	if [ -z "$types" ]; then
13295367Sdes		types="$i"
14295367Sdes		continue
15295367Sdes	fi
16295367Sdes	case "$i" in
17295367Sdes	*cert*)	types="$i,$types";;
18295367Sdes	*)	types="$types,$i";;
19295367Sdes	esac
20295367Sdesdone
21295367Sdes(
22295367Sdes	echo "HostKeyAlgorithms ${types}"
23295367Sdes	echo "PubkeyAcceptedKeyTypes *"
24295367Sdes) >> $OBJ/ssh_proxy
25204861Sdescp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
26295367Sdes(
27295367Sdes	echo "HostKeyAlgorithms *"
28295367Sdes	echo "PubkeyAcceptedKeyTypes *"
29295367Sdes) >> $OBJ/sshd_proxy_bak
30204861Sdes
31204861SdesHOSTS='localhost-with-alias,127.0.0.1,::1'
32204861Sdes
33295367Sdes# Create a CA key and add it to known hosts. Ed25519 chosed for speed.
34295367Sdes${SSHKEYGEN} -q -N '' -t ed25519  -f $OBJ/host_ca_key ||\
35204861Sdes	fail "ssh-keygen of host_ca_key failed"
36204861Sdes(
37255670Sdes	printf '@cert-authority '
38255670Sdes	printf "$HOSTS "
39204861Sdes	cat $OBJ/host_ca_key.pub
40295367Sdes) > $OBJ/known_hosts-cert.orig
41295367Sdescp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
42204861Sdes
43295367Sdes# Plain text revocation files
44295367Sdestouch $OBJ/host_revoked_empty
45295367Sdestouch $OBJ/host_revoked_plain
46295367Sdestouch $OBJ/host_revoked_cert
47295367Sdescp $OBJ/host_ca_key.pub $OBJ/host_revoked_ca
48295367Sdes
49262566SdesPLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
50262566Sdes
51295367Sdes# Prepare certificate, plain key and CA KRLs
52295367Sdes${SSHKEYGEN} -kf $OBJ/host_krl_empty || fatal "KRL init failed"
53295367Sdes${SSHKEYGEN} -kf $OBJ/host_krl_plain || fatal "KRL init failed"
54295367Sdes${SSHKEYGEN} -kf $OBJ/host_krl_cert || fatal "KRL init failed"
55295367Sdes${SSHKEYGEN} -kf $OBJ/host_krl_ca $OBJ/host_ca_key.pub \
56295367Sdes	|| fatal "KRL init failed"
57262566Sdes
58204861Sdes# Generate and sign host keys
59295367Sdesserial=1
60262566Sdesfor ktype in $PLAIN_TYPES ; do 
61204861Sdes	verbose "$tid: sign host ${ktype} cert"
62204861Sdes	# Generate and sign a host key
63204861Sdes	${SSHKEYGEN} -q -N '' -t ${ktype} \
64204861Sdes	    -f $OBJ/cert_host_key_${ktype} || \
65295367Sdes		fatal "ssh-keygen of cert_host_key_${ktype} failed"
66295367Sdes	${SSHKEYGEN} -ukf $OBJ/host_krl_plain \
67295367Sdes	    $OBJ/cert_host_key_${ktype}.pub || fatal "KRL update failed"
68295367Sdes	cat $OBJ/cert_host_key_${ktype}.pub >> $OBJ/host_revoked_plain
69295367Sdes	${SSHKEYGEN} -h -q -s $OBJ/host_ca_key -z $serial \
70204861Sdes	    -I "regress host key for $USER" \
71204861Sdes	    -n $HOSTS $OBJ/cert_host_key_${ktype} ||
72295367Sdes		fatal "couldn't sign cert_host_key_${ktype}"
73295367Sdes	${SSHKEYGEN} -ukf $OBJ/host_krl_cert \
74295367Sdes	    $OBJ/cert_host_key_${ktype}-cert.pub || \
75295367Sdes		fatal "KRL update failed"
76295367Sdes	cat $OBJ/cert_host_key_${ktype}-cert.pub >> $OBJ/host_revoked_cert
77295367Sdes	serial=`expr $serial + 1`
78204861Sdesdone
79204861Sdes
80295367Sdesattempt_connect() {
81295367Sdes	_ident="$1"
82295367Sdes	_expect_success="$2"
83295367Sdes	shift; shift
84295367Sdes	verbose "$tid: $_ident expect success $_expect_success"
85295367Sdes	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
86295367Sdes	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
87295367Sdes	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
88295367Sdes	    "$@" -F $OBJ/ssh_proxy somehost true
89295367Sdes	_r=$?
90295367Sdes	if [ "x$_expect_success" = "xyes" ] ; then
91295367Sdes		if [ $_r -ne 0 ]; then
92295367Sdes			fail "ssh cert connect $_ident failed"
93295367Sdes		fi
94295367Sdes	else
95295367Sdes		if [ $_r -eq 0 ]; then
96295367Sdes			fail "ssh cert connect $_ident succeeded unexpectedly"
97295367Sdes		fi
98295367Sdes	fi
99295367Sdes}
100295367Sdes
101295367Sdes# Basic connect and revocation tests.
102204861Sdesfor privsep in yes no ; do
103295367Sdes	for ktype in $PLAIN_TYPES ; do 
104204861Sdes		verbose "$tid: host ${ktype} cert connect privsep $privsep"
105204861Sdes		(
106204861Sdes			cat $OBJ/sshd_proxy_bak
107204861Sdes			echo HostKey $OBJ/cert_host_key_${ktype}
108204861Sdes			echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
109204861Sdes			echo UsePrivilegeSeparation $privsep
110204861Sdes		) > $OBJ/sshd_proxy
111204861Sdes
112295367Sdes		#               test name                         expect success
113295367Sdes		attempt_connect "$ktype basic connect"			"yes"
114295367Sdes		attempt_connect "$ktype empty KRL"			"yes" \
115295367Sdes		    -oRevokedHostKeys=$OBJ/host_krl_empty
116295367Sdes		attempt_connect "$ktype KRL w/ plain key revoked"	"no" \
117295367Sdes		    -oRevokedHostKeys=$OBJ/host_krl_plain
118295367Sdes		attempt_connect "$ktype KRL w/ cert revoked"		"no" \
119295367Sdes		    -oRevokedHostKeys=$OBJ/host_krl_cert
120295367Sdes		attempt_connect "$ktype KRL w/ CA revoked"		"no" \
121295367Sdes		    -oRevokedHostKeys=$OBJ/host_krl_ca
122295367Sdes		attempt_connect "$ktype empty plaintext revocation"	"yes" \
123295367Sdes		    -oRevokedHostKeys=$OBJ/host_revoked_empty
124295367Sdes		attempt_connect "$ktype plain key plaintext revocation"	"no" \
125295367Sdes		    -oRevokedHostKeys=$OBJ/host_revoked_plain
126295367Sdes		attempt_connect "$ktype cert plaintext revocation"	"no" \
127295367Sdes		    -oRevokedHostKeys=$OBJ/host_revoked_cert
128295367Sdes		attempt_connect "$ktype CA plaintext revocation"	"no" \
129295367Sdes		    -oRevokedHostKeys=$OBJ/host_revoked_ca
130204861Sdes	done
131204861Sdesdone
132204861Sdes
133204861Sdes# Revoked certificates with key present
134204861Sdes(
135255670Sdes	printf '@cert-authority '
136255670Sdes	printf "$HOSTS "
137204861Sdes	cat $OBJ/host_ca_key.pub
138295367Sdes	for ktype in $PLAIN_TYPES ; do
139262566Sdes		test -f "$OBJ/cert_host_key_${ktype}.pub" || fatal "no pubkey"
140262566Sdes		printf "@revoked * `cat $OBJ/cert_host_key_${ktype}.pub`\n"
141262566Sdes	done
142295367Sdes) > $OBJ/known_hosts-cert.orig
143295367Sdescp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
144204861Sdesfor privsep in yes no ; do
145295367Sdes	for ktype in $PLAIN_TYPES ; do 
146204861Sdes		verbose "$tid: host ${ktype} revoked cert privsep $privsep"
147204861Sdes		(
148204861Sdes			cat $OBJ/sshd_proxy_bak
149204861Sdes			echo HostKey $OBJ/cert_host_key_${ktype}
150204861Sdes			echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
151204861Sdes			echo UsePrivilegeSeparation $privsep
152204861Sdes		) > $OBJ/sshd_proxy
153204861Sdes
154295367Sdes		cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
155204861Sdes		${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
156204861Sdes		    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
157204861Sdes			-F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
158204861Sdes		if [ $? -eq 0 ]; then
159204861Sdes			fail "ssh cert connect succeeded unexpectedly"
160204861Sdes		fi
161204861Sdes	done
162204861Sdesdone
163204861Sdes
164204861Sdes# Revoked CA
165204861Sdes(
166255670Sdes	printf '@cert-authority '
167255670Sdes	printf "$HOSTS "
168204861Sdes	cat $OBJ/host_ca_key.pub
169255670Sdes	printf '@revoked '
170255670Sdes	printf "* "
171204861Sdes	cat $OBJ/host_ca_key.pub
172295367Sdes) > $OBJ/known_hosts-cert.orig
173295367Sdescp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
174295367Sdesfor ktype in $PLAIN_TYPES ; do 
175204861Sdes	verbose "$tid: host ${ktype} revoked cert"
176204861Sdes	(
177204861Sdes		cat $OBJ/sshd_proxy_bak
178204861Sdes		echo HostKey $OBJ/cert_host_key_${ktype}
179204861Sdes		echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
180204861Sdes	) > $OBJ/sshd_proxy
181295367Sdes	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
182204861Sdes	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
183204861Sdes	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
184204861Sdes		-F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
185204861Sdes	if [ $? -eq 0 ]; then
186204861Sdes		fail "ssh cert connect succeeded unexpectedly"
187204861Sdes	fi
188204861Sdesdone
189204861Sdes
190204861Sdes# Create a CA key and add it to known hosts
191204861Sdes(
192255670Sdes	printf '@cert-authority '
193255670Sdes	printf "$HOSTS "
194204861Sdes	cat $OBJ/host_ca_key.pub
195295367Sdes) > $OBJ/known_hosts-cert.orig
196295367Sdescp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
197204861Sdes
198204861Sdestest_one() {
199204861Sdes	ident=$1
200204861Sdes	result=$2
201204861Sdes	sign_opts=$3
202204861Sdes
203295367Sdes	for kt in rsa ed25519 ; do
204214979Sdes		${SSHKEYGEN} -q -s $OBJ/host_ca_key \
205214979Sdes		    -I "regress host key for $USER" \
206295367Sdes		    $sign_opts $OBJ/cert_host_key_${kt} ||
207214979Sdes			fail "couldn't sign cert_host_key_${kt}"
208214979Sdes		(
209214979Sdes			cat $OBJ/sshd_proxy_bak
210214979Sdes			echo HostKey $OBJ/cert_host_key_${kt}
211214979Sdes			echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
212214979Sdes		) > $OBJ/sshd_proxy
213214979Sdes	
214295367Sdes		cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
215214979Sdes		${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
216214979Sdes		    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
217214979Sdes		    -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
218214979Sdes		rc=$?
219214979Sdes		if [ "x$result" = "xsuccess" ] ; then
220214979Sdes			if [ $rc -ne 0 ]; then
221214979Sdes				fail "ssh cert connect $ident failed unexpectedly"
222214979Sdes			fi
223214979Sdes		else
224214979Sdes			if [ $rc -eq 0 ]; then
225214979Sdes				fail "ssh cert connect $ident succeeded unexpectedly"
226214979Sdes			fi
227204861Sdes		fi
228214979Sdes	done
229204861Sdes}
230204861Sdes
231204861Sdestest_one "user-certificate"	failure "-n $HOSTS"
232204861Sdestest_one "empty principals"	success "-h"
233204861Sdestest_one "wrong principals"	failure "-h -n foo"
234204861Sdestest_one "cert not yet valid"	failure "-h -V20200101:20300101"
235204861Sdestest_one "cert expired"		failure "-h -V19800101:19900101"
236204861Sdestest_one "cert valid interval"	success "-h -V-1w:+2w"
237204861Sdestest_one "cert has constraints"	failure "-h -Oforce-command=false"
238204861Sdes
239204861Sdes# Check downgrade of cert to raw key when no CA found
240295367Sdesfor ktype in $PLAIN_TYPES ; do 
241295367Sdes	rm -f $OBJ/known_hosts-cert $OBJ/cert_host_key*
242295367Sdes	verbose "$tid: host ${ktype} ${v} cert downgrade to raw key"
243295367Sdes	# Generate and sign a host key
244295367Sdes	${SSHKEYGEN} -q -N '' -t ${ktype} \
245295367Sdes	    -f $OBJ/cert_host_key_${ktype} || \
246295367Sdes		fail "ssh-keygen of cert_host_key_${ktype} failed"
247295367Sdes	${SSHKEYGEN} -t ${v} -h -q -s $OBJ/host_ca_key \
248295367Sdes	    -I "regress host key for $USER" \
249295367Sdes	    -n $HOSTS $OBJ/cert_host_key_${ktype} ||
250295367Sdes		fail "couldn't sign cert_host_key_${ktype}"
251295367Sdes	(
252295367Sdes		printf "$HOSTS "
253295367Sdes		cat $OBJ/cert_host_key_${ktype}.pub
254295367Sdes	) > $OBJ/known_hosts-cert
255295367Sdes	(
256295367Sdes		cat $OBJ/sshd_proxy_bak
257295367Sdes		echo HostKey $OBJ/cert_host_key_${ktype}
258295367Sdes		echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
259295367Sdes	) > $OBJ/sshd_proxy
260295367Sdes	
261295367Sdes	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
262295367Sdes	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
263295367Sdes		-F $OBJ/ssh_proxy somehost true
264295367Sdes	if [ $? -ne 0 ]; then
265295367Sdes		fail "ssh cert connect failed"
266295367Sdes	fi
267204861Sdesdone
268204861Sdes
269204861Sdes# Wrong certificate
270204861Sdes(
271255670Sdes	printf '@cert-authority '
272255670Sdes	printf "$HOSTS "
273204861Sdes	cat $OBJ/host_ca_key.pub
274295367Sdes) > $OBJ/known_hosts-cert.orig
275295367Sdescp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
276295367Sdesfor kt in $PLAIN_TYPES ; do 
277295367Sdes	rm -f $OBJ/cert_host_key*
278295367Sdes	# Self-sign key
279295367Sdes	${SSHKEYGEN} -q -N '' -t ${kt} \
280295367Sdes	    -f $OBJ/cert_host_key_${kt} || \
281295367Sdes		fail "ssh-keygen of cert_host_key_${kt} failed"
282295367Sdes	${SSHKEYGEN} -t ${v} -h -q -s $OBJ/cert_host_key_${kt} \
283295367Sdes	    -I "regress host key for $USER" \
284295367Sdes	    -n $HOSTS $OBJ/cert_host_key_${kt} ||
285295367Sdes		fail "couldn't sign cert_host_key_${kt}"
286295367Sdes	verbose "$tid: host ${kt} connect wrong cert"
287295367Sdes	(
288295367Sdes		cat $OBJ/sshd_proxy_bak
289295367Sdes		echo HostKey $OBJ/cert_host_key_${kt}
290295367Sdes		echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
291295367Sdes	) > $OBJ/sshd_proxy
292295367Sdes
293295367Sdes	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
294295367Sdes	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
295295367Sdes	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
296295367Sdes		-F $OBJ/ssh_proxy -q somehost true >/dev/null 2>&1
297295367Sdes	if [ $? -eq 0 ]; then
298295367Sdes		fail "ssh cert connect $ident succeeded unexpectedly"
299295367Sdes	fi
300204861Sdesdone
301204861Sdes
302295367Sdesrm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/cert_host_key*
303