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