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