#	$OpenBSD: hostkey-agent.sh,v 1.15 2024/12/04 10:51:13 dtucker Exp $
#	Placed in the Public Domain.

tid="hostkey agent"

rm -f $OBJ/agent-key.* $OBJ/ssh_proxy.orig $OBJ/agent-ca $OBJ/agent-ca.pub

trace "start agent"
eval `$SSHAGENT $EXTRA_AGENT_ARGS -s` > /dev/null
r=$?
[ $r -ne 0 ] && fatal "could not start ssh-agent: exit code $r"

grep -vi 'hostkey' $OBJ/sshd_proxy > $OBJ/sshd_proxy.orig
echo "HostKeyAgent $SSH_AUTH_SOCK" >> $OBJ/sshd_proxy.orig

trace "make CA key"

$SSHKEYGEN -qt ed25519 -N '' -f $OBJ/agent-ca || fatal "ssh-keygen CA"

trace "load hostkeys"
for k in $SSH_HOSTKEY_TYPES ; do
	AK=$OBJ/agent-key.$k
	$SSHKEYGEN -qt $k -N '' -f $AK || fatal "ssh-keygen $k failed"
	$SSHKEYGEN -s $OBJ/agent-ca -qh -n localhost-with-alias \
		-I localhost-with-alias $AK.pub || \
		fatal "sign $k failed"
	$SSHADD -k $AK >/dev/null 2>&1 || \
		fatal "could not load key $AK"
	# Remove private key so the server can't use it.
	rm $AK || fatal "could not remove $AK"
done
rm $OBJ/agent-ca # Don't need CA private any more either

unset SSH_AUTH_SOCK

for ps in $SSHD_PRIVSEP ; do
for k in $SSH_HOSTKEY_ALGS ; do
if $openssl_fips_prov ; then
	case $k in
	ssh-rsa)
		verbose "key algorithm $k privsep=$ps disallowed by fips provider"
		continue;;
	esac
fi
	verbose "key algorithm $k privsep=$ps"
	case $k in
	rsa-sha2-*) AK=$OBJ/agent-key.ssh-rsa;;
	*) AK=$OBJ/agent-key.$k;;
	esac
	cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
	echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
	echo "HostKeyAlgorithms $k" >> $OBJ/sshd_proxy
	echo "Hostkey $AK" >> $OBJ/sshd_proxy
	opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy"
	(
	printf 'localhost-with-alias,127.0.0.1,::1 ' ;
	cat $AK.pub
	) > $OBJ/known_hosts
	SSH_CONNECTION=`$SSH $opts host 'echo $SSH_CONNECTION'`
	if [ $? -ne 0 ]; then
		fail "key algorithm $k privsep=$ps failed"
	fi
	if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
		fail "bad SSH_CONNECTION key algorithm $k privsep=$ps"
	fi
done
done

# Prepare sshd_proxy for custom certificates.
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
for k in $SSH_HOSTKEY_TYPES ; do
	AK=$OBJ/agent-key.$k
	test -f $AK.pub || fatal "no $k key"
	test -f $AK-cert.pub || fatal "no $k cert"
	echo "Hostkey $AK" >> $OBJ/sshd_proxy
	echo "HostCertificate $AK-cert.pub" >> $OBJ/sshd_proxy
done
SSH_CERTTYPES=`$SSH -Q key-cert`
HOSTKEYALGS=`echo $SSH_CERTTYPES | tr ' ' ','`
echo "HostKeyAlgorithms $HOSTKEYALGS" >> $OBJ/sshd_proxy
cp $OBJ/sshd_proxy $OBJ/sshd_proxy.orig

# Add only CA trust anchor to known_hosts.
(
printf '@cert-authority localhost-with-alias '
cat $OBJ/agent-ca.pub
) > $OBJ/known_hosts

for ps in $SSHD_PRIVSEP ; do
for k in $SSH_CERTTYPES ; do
if $openssl_fips_prov ; then
	case $k in
	ssh-rsa-cert-*)
		verbose "cert type $k privsep=$ps disallowed by fips provider"
		continue;;
	esac
fi
	verbose "cert type $k privsep=$ps"
	cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
	echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
	opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy"
	SSH_CONNECTION=`$SSH $opts host 'echo $SSH_CONNECTION'`
	if test $? -ne 0 ; then
		fail "cert type $k privsep=$ps failed"
	fi
	if test "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ; then
		fail "bad SSH_CONNECTION cert type $k privsep=$ps"
	fi
done
done

verbose "multiple hostkeys"
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
cp $OBJ/ssh_proxy $OBJ/ssh_proxy.orig
grep -vi 'globalknownhostsfile' $OBJ/ssh_proxy.orig > $OBJ/ssh_proxy
echo "UpdateHostkeys=yes" >> $OBJ/ssh_proxy
echo "GlobalKnownHostsFile=none" >> $OBJ/ssh_proxy

> $OBJ/known_hosts
for k in $SSH_HOSTKEY_TYPES ; do
	AK="$OBJ/agent-key.$k"
	verbose "  add key type $k"
	echo "Hostkey $AK" >> $OBJ/sshd_proxy
	(
	printf 'localhost-with-alias '
	cat $AK.pub
	) >> $OBJ/known_hosts
done

opts="-oStrictHostKeyChecking=yes -F $OBJ/ssh_proxy"
SSH_CONNECTION=`$SSH $opts host 'echo $SSH_CONNECTION'`
if test $? -ne 0 ; then
	fail "connection to server with multiple hostkeys failed"
fi
if test "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ; then
	fail "bad SSH_CONNECTION key while using multiple hostkeys"
fi

trace "kill agent"
$SSHAGENT -k > /dev/null

rm $OBJ/agent-ca.pub
rm $OBJ/known_hosts
