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