cert-hostkey.sh revision 323120
1#	$OpenBSD: cert-hostkey.sh,v 1.14 2016/05/02 09:52:00 djm Exp $
2#	Placed in the Public Domain.
3
4tid="certified host keys"
5
6rm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/host_revoked_*
7rm -f $OBJ/cert_host_key* $OBJ/host_krl_*
8
9# Allow all hostkey/pubkey types, prefer certs for the client
10types=""
11for i in `$SSH -Q key`; do
12	if [ -z "$types" ]; then
13		types="$i"
14		continue
15	fi
16	case "$i" in
17	*cert*)	types="$i,$types";;
18	*)	types="$types,$i";;
19	esac
20done
21(
22	echo "HostKeyAlgorithms ${types}"
23	echo "PubkeyAcceptedKeyTypes *"
24) >> $OBJ/ssh_proxy
25cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
26(
27	echo "HostKeyAlgorithms *"
28	echo "PubkeyAcceptedKeyTypes *"
29) >> $OBJ/sshd_proxy_bak
30
31HOSTS='localhost-with-alias,127.0.0.1,::1'
32
33kh_ca() {
34	for k in "$@" ; do
35		printf "@cert-authority $HOSTS "
36		cat $OBJ/$k || fatal "couldn't cat $k"
37	done
38}
39kh_revoke() {
40	for k in "$@" ; do
41		printf "@revoked * "
42		cat $OBJ/$k || fatal "couldn't cat $k"
43	done
44}
45
46# Create a CA key and add it to known hosts. Ed25519 chosen for speed.
47# RSA for testing RSA/SHA2 signatures.
48${SSHKEYGEN} -q -N '' -t ed25519  -f $OBJ/host_ca_key ||\
49	fail "ssh-keygen of host_ca_key failed"
50${SSHKEYGEN} -q -N '' -t rsa  -f $OBJ/host_ca_key2 ||\
51	fail "ssh-keygen of host_ca_key failed"
52
53kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
54cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
55
56# Plain text revocation files
57touch $OBJ/host_revoked_empty
58touch $OBJ/host_revoked_plain
59touch $OBJ/host_revoked_cert
60cat $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub > $OBJ/host_revoked_ca
61
62PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'`
63
64if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then
65	PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512"
66fi
67
68# Prepare certificate, plain key and CA KRLs
69${SSHKEYGEN} -kf $OBJ/host_krl_empty || fatal "KRL init failed"
70${SSHKEYGEN} -kf $OBJ/host_krl_plain || fatal "KRL init failed"
71${SSHKEYGEN} -kf $OBJ/host_krl_cert || fatal "KRL init failed"
72${SSHKEYGEN} -kf $OBJ/host_krl_ca $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub \
73	|| fatal "KRL init failed"
74
75# Generate and sign host keys
76serial=1
77for ktype in $PLAIN_TYPES ; do
78	verbose "$tid: sign host ${ktype} cert"
79	# Generate and sign a host key
80	${SSHKEYGEN} -q -N '' -t ${ktype} \
81	    -f $OBJ/cert_host_key_${ktype} || \
82		fatal "ssh-keygen of cert_host_key_${ktype} failed"
83	${SSHKEYGEN} -ukf $OBJ/host_krl_plain \
84	    $OBJ/cert_host_key_${ktype}.pub || fatal "KRL update failed"
85	cat $OBJ/cert_host_key_${ktype}.pub >> $OBJ/host_revoked_plain
86	case $ktype in
87	rsa-sha2-*)	tflag="-t $ktype"; ca="$OBJ/host_ca_key2" ;;
88	*)		tflag=""; ca="$OBJ/host_ca_key" ;;
89	esac
90	${SSHKEYGEN} -h -q -s $ca -z $serial $tflag \
91	    -I "regress host key for $USER" \
92	    -n $HOSTS $OBJ/cert_host_key_${ktype} ||
93		fatal "couldn't sign cert_host_key_${ktype}"
94	${SSHKEYGEN} -ukf $OBJ/host_krl_cert \
95	    $OBJ/cert_host_key_${ktype}-cert.pub || \
96		fatal "KRL update failed"
97	cat $OBJ/cert_host_key_${ktype}-cert.pub >> $OBJ/host_revoked_cert
98	serial=`expr $serial + 1`
99done
100
101attempt_connect() {
102	_ident="$1"
103	_expect_success="$2"
104	shift; shift
105	verbose "$tid: $_ident expect success $_expect_success"
106	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
107	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
108	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
109	    "$@" -F $OBJ/ssh_proxy somehost true
110	_r=$?
111	if [ "x$_expect_success" = "xyes" ] ; then
112		if [ $_r -ne 0 ]; then
113			fail "ssh cert connect $_ident failed"
114		fi
115	else
116		if [ $_r -eq 0 ]; then
117			fail "ssh cert connect $_ident succeeded unexpectedly"
118		fi
119	fi
120}
121
122# Basic connect and revocation tests.
123for privsep in yes no ; do
124	for ktype in $PLAIN_TYPES ; do
125		verbose "$tid: host ${ktype} cert connect privsep $privsep"
126		(
127			cat $OBJ/sshd_proxy_bak
128			echo HostKey $OBJ/cert_host_key_${ktype}
129			echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
130			echo UsePrivilegeSeparation $privsep
131		) > $OBJ/sshd_proxy
132
133		#               test name                         expect success
134		attempt_connect "$ktype basic connect"			"yes"
135		attempt_connect "$ktype empty KRL"			"yes" \
136		    -oRevokedHostKeys=$OBJ/host_krl_empty
137		attempt_connect "$ktype KRL w/ plain key revoked"	"no" \
138		    -oRevokedHostKeys=$OBJ/host_krl_plain
139		attempt_connect "$ktype KRL w/ cert revoked"		"no" \
140		    -oRevokedHostKeys=$OBJ/host_krl_cert
141		attempt_connect "$ktype KRL w/ CA revoked"		"no" \
142		    -oRevokedHostKeys=$OBJ/host_krl_ca
143		attempt_connect "$ktype empty plaintext revocation"	"yes" \
144		    -oRevokedHostKeys=$OBJ/host_revoked_empty
145		attempt_connect "$ktype plain key plaintext revocation"	"no" \
146		    -oRevokedHostKeys=$OBJ/host_revoked_plain
147		attempt_connect "$ktype cert plaintext revocation"	"no" \
148		    -oRevokedHostKeys=$OBJ/host_revoked_cert
149		attempt_connect "$ktype CA plaintext revocation"	"no" \
150		    -oRevokedHostKeys=$OBJ/host_revoked_ca
151	done
152done
153
154# Revoked certificates with key present
155kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
156for ktype in $PLAIN_TYPES ; do
157	test -f "$OBJ/cert_host_key_${ktype}.pub" || fatal "no pubkey"
158	kh_revoke cert_host_key_${ktype}.pub >> $OBJ/known_hosts-cert.orig
159done
160cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
161for privsep in yes no ; do
162	for ktype in $PLAIN_TYPES ; do
163		verbose "$tid: host ${ktype} revoked cert privsep $privsep"
164		(
165			cat $OBJ/sshd_proxy_bak
166			echo HostKey $OBJ/cert_host_key_${ktype}
167			echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
168			echo UsePrivilegeSeparation $privsep
169		) > $OBJ/sshd_proxy
170
171		cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
172		${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
173		    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
174			-F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
175		if [ $? -eq 0 ]; then
176			fail "ssh cert connect succeeded unexpectedly"
177		fi
178	done
179done
180
181# Revoked CA
182kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
183kh_revoke host_ca_key.pub host_ca_key2.pub >> $OBJ/known_hosts-cert.orig
184cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
185for ktype in $PLAIN_TYPES ; do
186	verbose "$tid: host ${ktype} revoked cert"
187	(
188		cat $OBJ/sshd_proxy_bak
189		echo HostKey $OBJ/cert_host_key_${ktype}
190		echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
191	) > $OBJ/sshd_proxy
192	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
193	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
194	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
195		-F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
196	if [ $? -eq 0 ]; then
197		fail "ssh cert connect succeeded unexpectedly"
198	fi
199done
200
201# Create a CA key and add it to known hosts
202kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
203cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
204
205test_one() {
206	ident=$1
207	result=$2
208	sign_opts=$3
209
210	for kt in rsa ed25519 ; do
211		case $ktype in
212		rsa-sha2-*)	tflag="-t $ktype"; ca="$OBJ/host_ca_key2" ;;
213		*)		tflag=""; ca="$OBJ/host_ca_key" ;;
214		esac
215		${SSHKEYGEN} -q -s $ca $tflag -I "regress host key for $USER" \
216		    $sign_opts $OBJ/cert_host_key_${kt} ||
217			fatal "couldn't sign cert_host_key_${kt}"
218		(
219			cat $OBJ/sshd_proxy_bak
220			echo HostKey $OBJ/cert_host_key_${kt}
221			echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
222		) > $OBJ/sshd_proxy
223
224		cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
225		${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
226		    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
227		    -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
228		rc=$?
229		if [ "x$result" = "xsuccess" ] ; then
230			if [ $rc -ne 0 ]; then
231				fail "ssh cert connect $ident failed unexpectedly"
232			fi
233		else
234			if [ $rc -eq 0 ]; then
235				fail "ssh cert connect $ident succeeded unexpectedly"
236			fi
237		fi
238	done
239}
240
241test_one "user-certificate"	failure "-n $HOSTS"
242test_one "empty principals"	success "-h"
243test_one "wrong principals"	failure "-h -n foo"
244test_one "cert not yet valid"	failure "-h -V20200101:20300101"
245test_one "cert expired"		failure "-h -V19800101:19900101"
246test_one "cert valid interval"	success "-h -V-1w:+2w"
247test_one "cert has constraints"	failure "-h -Oforce-command=false"
248
249# Check downgrade of cert to raw key when no CA found
250for ktype in $PLAIN_TYPES ; do
251	rm -f $OBJ/known_hosts-cert $OBJ/cert_host_key*
252	verbose "$tid: host ${ktype} ${v} cert downgrade to raw key"
253	# Generate and sign a host key
254	${SSHKEYGEN} -q -N '' -t ${ktype} -f $OBJ/cert_host_key_${ktype} || \
255		fail "ssh-keygen of cert_host_key_${ktype} failed"
256	case $ktype in
257	rsa-sha2-*)	tflag="-t $ktype"; ca="$OBJ/host_ca_key2" ;;
258	*)		tflag=""; ca="$OBJ/host_ca_key" ;;
259	esac
260	${SSHKEYGEN} -h -q $tflag -s $ca $tflag \
261	    -I "regress host key for $USER" \
262	    -n $HOSTS $OBJ/cert_host_key_${ktype} ||
263		fatal "couldn't sign cert_host_key_${ktype}"
264	(
265		printf "$HOSTS "
266		cat $OBJ/cert_host_key_${ktype}.pub
267	) > $OBJ/known_hosts-cert
268	(
269		cat $OBJ/sshd_proxy_bak
270		echo HostKey $OBJ/cert_host_key_${ktype}
271		echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
272	) > $OBJ/sshd_proxy
273
274	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
275	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
276		-F $OBJ/ssh_proxy somehost true
277	if [ $? -ne 0 ]; then
278		fail "ssh cert connect failed"
279	fi
280done
281
282# Wrong certificate
283kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
284cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
285for kt in $PLAIN_TYPES ; do
286	verbose "$tid: host ${kt} connect wrong cert"
287	rm -f $OBJ/cert_host_key*
288	# Self-sign key
289	${SSHKEYGEN} -q -N '' -t ${kt} -f $OBJ/cert_host_key_${kt} || \
290		fail "ssh-keygen of cert_host_key_${kt} failed"
291	case $kt in
292	rsa-sha2-*)	tflag="-t $kt" ;;
293	*)		tflag="" ;;
294	esac
295	${SSHKEYGEN} $tflag -h -q -s $OBJ/cert_host_key_${kt} \
296	    -I "regress host key for $USER" \
297	    -n $HOSTS $OBJ/cert_host_key_${kt} ||
298		fatal "couldn't sign cert_host_key_${kt}"
299	(
300		cat $OBJ/sshd_proxy_bak
301		echo HostKey $OBJ/cert_host_key_${kt}
302		echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
303	) > $OBJ/sshd_proxy
304
305	cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
306	${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
307	    -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
308		-F $OBJ/ssh_proxy -q somehost true >/dev/null 2>&1
309	if [ $? -eq 0 ]; then
310		fail "ssh cert connect $ident succeeded unexpectedly"
311	fi
312done
313
314rm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/cert_host_key*
315