cert-userkey.sh revision 1.21
1# $OpenBSD: cert-userkey.sh,v 1.21 2019/07/25 08:28:15 dtucker Exp $ 2# Placed in the Public Domain. 3 4tid="certified user keys" 5 6rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key* 7cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak 8cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak 9 10PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` 11EXTRA_TYPES="" 12rsa="" 13 14if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then 15 rsa=rsa 16 PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512" 17fi 18 19kname() { 20 case $ktype in 21 rsa-sha2-*) n="$ktype" ;; 22 # subshell because some seds will add a newline 23 *) n=$(echo $1 | sed 's/^dsa/ssh-dss/;s/^rsa/ssh-rsa/;s/^ed/ssh-ed/') ;; 24 esac 25 if [ -z "$rsa" ]; then 26 echo "$n*,ssh-ed25519*" 27 else 28 echo "$n*,ssh-rsa*,ssh-ed25519*" 29 fi 30} 31 32# Create a CA key 33if [ ! -z "$rsa" ]; then 34 catype=rsa 35else 36 catype=ed25519 37fi 38${SSHKEYGEN} -q -N '' -t $catype -f $OBJ/user_ca_key ||\ 39 fail "ssh-keygen of user_ca_key failed" 40 41# Generate and sign user keys 42for ktype in $PLAIN_TYPES $EXTRA_TYPES ; do 43 verbose "$tid: sign user ${ktype} cert" 44 ${SSHKEYGEN} -q -N '' -t ${ktype} \ 45 -f $OBJ/cert_user_key_${ktype} || \ 46 fatal "ssh-keygen of cert_user_key_${ktype} failed" 47 # Generate RSA/SHA2 certs for rsa-sha2* keys. 48 case $ktype in 49 rsa-sha2-*) tflag="-t $ktype" ;; 50 *) tflag="" ;; 51 esac 52 ${SSHKEYGEN} -q -s $OBJ/user_ca_key -z $$ \ 53 -I "regress user key for $USER" \ 54 -n ${USER},mekmitasdigoat $tflag $OBJ/cert_user_key_${ktype} || \ 55 fatal "couldn't sign cert_user_key_${ktype}" 56done 57 58# Test explicitly-specified principals 59for ktype in $EXTRA_TYPES $PLAIN_TYPES ; do 60 t=$(kname $ktype) 61 for privsep in yes sandbox ; do 62 _prefix="${ktype} privsep $privsep" 63 64 # Setup for AuthorizedPrincipalsFile 65 rm -f $OBJ/authorized_keys_$USER 66 ( 67 cat $OBJ/sshd_proxy_bak 68 echo "UsePrivilegeSeparation $privsep" 69 echo "AuthorizedPrincipalsFile " \ 70 "$OBJ/authorized_principals_%u" 71 echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" 72 echo "PubkeyAcceptedKeyTypes ${t}" 73 ) > $OBJ/sshd_proxy 74 ( 75 cat $OBJ/ssh_proxy_bak 76 echo "PubkeyAcceptedKeyTypes ${t}" 77 ) > $OBJ/ssh_proxy 78 79 # Missing authorized_principals 80 verbose "$tid: ${_prefix} missing authorized_principals" 81 rm -f $OBJ/authorized_principals_$USER 82 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 83 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 84 if [ $? -eq 0 ]; then 85 fail "ssh cert connect succeeded unexpectedly" 86 fi 87 88 # Empty authorized_principals 89 verbose "$tid: ${_prefix} empty authorized_principals" 90 echo > $OBJ/authorized_principals_$USER 91 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 92 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 93 if [ $? -eq 0 ]; then 94 fail "ssh cert connect succeeded unexpectedly" 95 fi 96 97 # Wrong authorized_principals 98 verbose "$tid: ${_prefix} wrong authorized_principals" 99 echo gregorsamsa > $OBJ/authorized_principals_$USER 100 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 101 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 102 if [ $? -eq 0 ]; then 103 fail "ssh cert connect succeeded unexpectedly" 104 fi 105 106 # Correct authorized_principals 107 verbose "$tid: ${_prefix} correct authorized_principals" 108 echo mekmitasdigoat > $OBJ/authorized_principals_$USER 109 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 110 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 111 if [ $? -ne 0 ]; then 112 fail "ssh cert connect failed" 113 fi 114 115 # authorized_principals with bad key option 116 verbose "$tid: ${_prefix} authorized_principals bad key opt" 117 echo 'blah mekmitasdigoat' > $OBJ/authorized_principals_$USER 118 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 119 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 120 if [ $? -eq 0 ]; then 121 fail "ssh cert connect succeeded unexpectedly" 122 fi 123 124 # authorized_principals with command=false 125 verbose "$tid: ${_prefix} authorized_principals command=false" 126 echo 'command="false" mekmitasdigoat' > \ 127 $OBJ/authorized_principals_$USER 128 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 129 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 130 if [ $? -eq 0 ]; then 131 fail "ssh cert connect succeeded unexpectedly" 132 fi 133 134 135 # authorized_principals with command=true 136 verbose "$tid: ${_prefix} authorized_principals command=true" 137 echo 'command="true" mekmitasdigoat' > \ 138 $OBJ/authorized_principals_$USER 139 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 140 -F $OBJ/ssh_proxy somehost false >/dev/null 2>&1 141 if [ $? -ne 0 ]; then 142 fail "ssh cert connect failed" 143 fi 144 145 # Setup for principals= key option 146 rm -f $OBJ/authorized_principals_$USER 147 ( 148 cat $OBJ/sshd_proxy_bak 149 echo "UsePrivilegeSeparation $privsep" 150 echo "PubkeyAcceptedKeyTypes ${t}" 151 ) > $OBJ/sshd_proxy 152 ( 153 cat $OBJ/ssh_proxy_bak 154 echo "PubkeyAcceptedKeyTypes ${t}" 155 ) > $OBJ/ssh_proxy 156 157 # Wrong principals list 158 verbose "$tid: ${_prefix} wrong principals key option" 159 ( 160 printf 'cert-authority,principals="gregorsamsa" ' 161 cat $OBJ/user_ca_key.pub 162 ) > $OBJ/authorized_keys_$USER 163 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 164 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 165 if [ $? -eq 0 ]; then 166 fail "ssh cert connect succeeded unexpectedly" 167 fi 168 169 # Correct principals list 170 verbose "$tid: ${_prefix} correct principals key option" 171 ( 172 printf 'cert-authority,principals="mekmitasdigoat" ' 173 cat $OBJ/user_ca_key.pub 174 ) > $OBJ/authorized_keys_$USER 175 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 176 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 177 if [ $? -ne 0 ]; then 178 fail "ssh cert connect failed" 179 fi 180 done 181done 182 183basic_tests() { 184 auth=$1 185 if test "x$auth" = "xauthorized_keys" ; then 186 # Add CA to authorized_keys 187 ( 188 printf 'cert-authority ' 189 cat $OBJ/user_ca_key.pub 190 ) > $OBJ/authorized_keys_$USER 191 else 192 echo > $OBJ/authorized_keys_$USER 193 extra_sshd="TrustedUserCAKeys $OBJ/user_ca_key.pub" 194 fi 195 196 for ktype in $PLAIN_TYPES ; do 197 t=$(kname $ktype) 198 for privsep in yes no ; do 199 _prefix="${ktype} privsep $privsep $auth" 200 # Simple connect 201 verbose "$tid: ${_prefix} connect" 202 ( 203 cat $OBJ/sshd_proxy_bak 204 echo "UsePrivilegeSeparation $privsep" 205 echo "PubkeyAcceptedKeyTypes ${t}" 206 echo "$extra_sshd" 207 ) > $OBJ/sshd_proxy 208 ( 209 cat $OBJ/ssh_proxy_bak 210 echo "PubkeyAcceptedKeyTypes ${t}" 211 ) > $OBJ/ssh_proxy 212 213 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 214 -F $OBJ/ssh_proxy somehost true 215 if [ $? -ne 0 ]; then 216 fail "ssh cert connect failed" 217 fi 218 219 # Revoked keys 220 verbose "$tid: ${_prefix} revoked key" 221 ( 222 cat $OBJ/sshd_proxy_bak 223 echo "UsePrivilegeSeparation $privsep" 224 echo "RevokedKeys $OBJ/cert_user_key_revoked" 225 echo "PubkeyAcceptedKeyTypes ${t}" 226 echo "$extra_sshd" 227 ) > $OBJ/sshd_proxy 228 cp $OBJ/cert_user_key_${ktype}.pub \ 229 $OBJ/cert_user_key_revoked 230 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 231 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 232 if [ $? -eq 0 ]; then 233 fail "ssh cert connect succeeded unexpecedly" 234 fi 235 verbose "$tid: ${_prefix} revoked via KRL" 236 rm $OBJ/cert_user_key_revoked 237 ${SSHKEYGEN} -kqf $OBJ/cert_user_key_revoked \ 238 $OBJ/cert_user_key_${ktype}.pub 239 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 240 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 241 if [ $? -eq 0 ]; then 242 fail "ssh cert connect succeeded unexpecedly" 243 fi 244 verbose "$tid: ${_prefix} empty KRL" 245 ${SSHKEYGEN} -kqf $OBJ/cert_user_key_revoked 246 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 247 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 248 if [ $? -ne 0 ]; then 249 fail "ssh cert connect failed" 250 fi 251 done 252 253 # Revoked CA 254 verbose "$tid: ${ktype} $auth revoked CA key" 255 ( 256 cat $OBJ/sshd_proxy_bak 257 echo "RevokedKeys $OBJ/user_ca_key.pub" 258 echo "PubkeyAcceptedKeyTypes ${t}" 259 echo "$extra_sshd" 260 ) > $OBJ/sshd_proxy 261 ${SSH} -i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \ 262 somehost true >/dev/null 2>&1 263 if [ $? -eq 0 ]; then 264 fail "ssh cert connect succeeded unexpecedly" 265 fi 266 done 267 268 verbose "$tid: $auth CA does not authenticate" 269 ( 270 cat $OBJ/sshd_proxy_bak 271 echo "PubkeyAcceptedKeyTypes ${t}" 272 echo "$extra_sshd" 273 ) > $OBJ/sshd_proxy 274 verbose "$tid: ensure CA key does not authenticate user" 275 ${SSH} -i $OBJ/user_ca_key \ 276 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 277 if [ $? -eq 0 ]; then 278 fail "ssh cert connect with CA key succeeded unexpectedly" 279 fi 280} 281 282basic_tests authorized_keys 283basic_tests TrustedUserCAKeys 284 285test_one() { 286 ident=$1 287 result=$2 288 sign_opts=$3 289 auth_choice=$4 290 auth_opt=$5 291 292 if test "x$auth_choice" = "x" ; then 293 auth_choice="authorized_keys TrustedUserCAKeys" 294 fi 295 296 for auth in $auth_choice ; do 297 for ktype in $rsa ed25519 ; do 298 cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy 299 if test "x$auth" = "xauthorized_keys" ; then 300 # Add CA to authorized_keys 301 ( 302 printf "cert-authority${auth_opt} " 303 cat $OBJ/user_ca_key.pub 304 ) > $OBJ/authorized_keys_$USER 305 else 306 echo > $OBJ/authorized_keys_$USER 307 echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" \ 308 >> $OBJ/sshd_proxy 309 echo "PubkeyAcceptedKeyTypes ${t}*" \ 310 >> $OBJ/sshd_proxy 311 if test "x$auth_opt" != "x" ; then 312 echo $auth_opt >> $OBJ/sshd_proxy 313 fi 314 fi 315 316 verbose "$tid: $ident auth $auth expect $result $ktype" 317 ${SSHKEYGEN} -q -s $OBJ/user_ca_key \ 318 -I "regress user key for $USER" \ 319 $sign_opts $OBJ/cert_user_key_${ktype} || 320 fail "couldn't sign cert_user_key_${ktype}" 321 322 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 323 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 324 rc=$? 325 if [ "x$result" = "xsuccess" ] ; then 326 if [ $rc -ne 0 ]; then 327 fail "$ident failed unexpectedly" 328 fi 329 else 330 if [ $rc -eq 0 ]; then 331 fail "$ident succeeded unexpectedly" 332 fi 333 fi 334 done 335 done 336} 337 338test_one "correct principal" success "-n ${USER}" 339test_one "host-certificate" failure "-n ${USER} -h" 340test_one "wrong principals" failure "-n foo" 341test_one "cert not yet valid" failure "-n ${USER} -V20200101:20300101" 342test_one "cert expired" failure "-n ${USER} -V19800101:19900101" 343test_one "cert valid interval" success "-n ${USER} -V-1w:+2w" 344test_one "wrong source-address" failure "-n ${USER} -Osource-address=10.0.0.0/8" 345test_one "force-command" failure "-n ${USER} -Oforce-command=false" 346 347# Behaviour is different here: TrustedUserCAKeys doesn't allow empty principals 348test_one "empty principals" success "" authorized_keys 349test_one "empty principals" failure "" TrustedUserCAKeys 350 351# Check explicitly-specified principals: an empty principals list in the cert 352# should always be refused. 353 354# AuthorizedPrincipalsFile 355rm -f $OBJ/authorized_keys_$USER 356echo mekmitasdigoat > $OBJ/authorized_principals_$USER 357test_one "AuthorizedPrincipalsFile principals" success "-n mekmitasdigoat" \ 358 TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" 359test_one "AuthorizedPrincipalsFile no principals" failure "" \ 360 TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" 361 362# principals= key option 363rm -f $OBJ/authorized_principals_$USER 364test_one "principals key option principals" success "-n mekmitasdigoat" \ 365 authorized_keys ',principals="mekmitasdigoat"' 366test_one "principals key option no principals" failure "" \ 367 authorized_keys ',principals="mekmitasdigoat"' 368 369# command= options vs. force-command in key 370test_one "force-command match true" success \ 371 "-n ${USER} -Oforce-command=true" \ 372 authorized_keys ',command="true"' 373test_one "force-command match true" failure \ 374 "-n ${USER} -Oforce-command=false" \ 375 authorized_keys ',command="false"' 376test_one "force-command mismatch 1" failure \ 377 "-n ${USER} -Oforce-command=false" \ 378 authorized_keys ',command="true"' 379test_one "force-command mismatch 2" failure \ 380 "-n ${USER} -Oforce-command=true" \ 381 authorized_keys ',command="false"' 382 383# Wrong certificate 384cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy 385for ktype in $PLAIN_TYPES ; do 386 t=$(kname $ktype) 387 # Self-sign 388 ${SSHKEYGEN} -q -s $OBJ/cert_user_key_${ktype} -I \ 389 "regress user key for $USER" \ 390 -n $USER $OBJ/cert_user_key_${ktype} || 391 fatal "couldn't sign cert_user_key_${ktype}" 392 verbose "$tid: user ${ktype} connect wrong cert" 393 ${SSH} -i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \ 394 somehost true >/dev/null 2>&1 395 if [ $? -eq 0 ]; then 396 fail "ssh cert connect $ident succeeded unexpectedly" 397 fi 398done 399 400rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key* 401rm -f $OBJ/authorized_principals_$USER 402 403