1# $OpenBSD: cert-userkey.sh,v 1.28 2021/09/30 05:26:26 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 | maybe_filter_sk | 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 $1 in 21 rsa-sha2-*) n="$1" ;; 22 sk-ecdsa-*) n="sk-ecdsa" ;; 23 sk-ssh-ed25519*) n="sk-ssh-ed25519" ;; 24 # subshell because some seds will add a newline 25 *) n=$(echo $1 | sed 's/^dsa/ssh-dss/;s/^rsa/ssh-rsa/;s/^ed/ssh-ed/') ;; 26 esac 27 if [ -z "$rsa" ]; then 28 echo "$n*,ssh-ed25519*" 29 else 30 echo "$n*,ssh-rsa*,ssh-ed25519*" 31 fi 32} 33 34# Create a CA key 35if [ ! -z "$rsa" ]; then 36 catype=rsa 37else 38 catype=ed25519 39fi 40${SSHKEYGEN} -q -N '' -t $catype -f $OBJ/user_ca_key ||\ 41 fail "ssh-keygen of user_ca_key failed" 42 43# Generate and sign user keys 44for ktype in $PLAIN_TYPES $EXTRA_TYPES ; do 45 verbose "$tid: sign user ${ktype} cert" 46 ${SSHKEYGEN} -q -N '' -t ${ktype} \ 47 -f $OBJ/cert_user_key_${ktype} || \ 48 fatal "ssh-keygen of cert_user_key_${ktype} failed" 49 # Generate RSA/SHA2 certs for rsa-sha2* keys. 50 case $ktype in 51 rsa-sha2-*) tflag="-t $ktype" ;; 52 *) tflag="" ;; 53 esac 54 ${SSHKEYGEN} -q -s $OBJ/user_ca_key -z $$ \ 55 -I "regress user key for $USER" \ 56 -n ${USER},mekmitasdigoat $tflag $OBJ/cert_user_key_${ktype} || \ 57 fatal "couldn't sign cert_user_key_${ktype}" 58done 59 60# Test explicitly-specified principals 61for ktype in $EXTRA_TYPES $PLAIN_TYPES ; do 62 t=$(kname $ktype) 63 _prefix="${ktype}" 64 65 # Setup for AuthorizedPrincipalsFile 66 rm -f $OBJ/authorized_keys_$USER 67 ( 68 cat $OBJ/sshd_proxy_bak 69 echo "AuthorizedPrincipalsFile " \ 70 "$OBJ/authorized_principals_%u" 71 echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" 72 echo "PubkeyAcceptedAlgorithms ${t}" 73 ) > $OBJ/sshd_proxy 74 ( 75 cat $OBJ/ssh_proxy_bak 76 echo "PubkeyAcceptedAlgorithms ${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 "PubkeyAcceptedAlgorithms ${t}" 150 ) > $OBJ/sshd_proxy 151 ( 152 cat $OBJ/ssh_proxy_bak 153 echo "PubkeyAcceptedAlgorithms ${t}" 154 ) > $OBJ/ssh_proxy 155 156 # Wrong principals list 157 verbose "$tid: ${_prefix} wrong principals key option" 158 ( 159 printf 'cert-authority,principals="gregorsamsa" ' 160 cat $OBJ/user_ca_key.pub 161 ) > $OBJ/authorized_keys_$USER 162 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 163 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 164 if [ $? -eq 0 ]; then 165 fail "ssh cert connect succeeded unexpectedly" 166 fi 167 168 # Correct principals list 169 verbose "$tid: ${_prefix} correct principals key option" 170 ( 171 printf 'cert-authority,principals="mekmitasdigoat" ' 172 cat $OBJ/user_ca_key.pub 173 ) > $OBJ/authorized_keys_$USER 174 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 175 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 176 if [ $? -ne 0 ]; then 177 fail "ssh cert connect failed" 178 fi 179done 180 181basic_tests() { 182 auth=$1 183 if test "x$auth" = "xauthorized_keys" ; then 184 # Add CA to authorized_keys 185 ( 186 printf 'cert-authority ' 187 cat $OBJ/user_ca_key.pub 188 ) > $OBJ/authorized_keys_$USER 189 else 190 echo > $OBJ/authorized_keys_$USER 191 extra_sshd="TrustedUserCAKeys $OBJ/user_ca_key.pub" 192 fi 193 194 for ktype in $PLAIN_TYPES ; do 195 t=$(kname $ktype) 196 _prefix="${ktype} $auth" 197 # Simple connect 198 verbose "$tid: ${_prefix} connect" 199 ( 200 cat $OBJ/sshd_proxy_bak 201 echo "PubkeyAcceptedAlgorithms ${t}" 202 echo "$extra_sshd" 203 ) > $OBJ/sshd_proxy 204 ( 205 cat $OBJ/ssh_proxy_bak 206 echo "PubkeyAcceptedAlgorithms ${t}" 207 ) > $OBJ/ssh_proxy 208 209 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 210 -F $OBJ/ssh_proxy somehost true 211 if [ $? -ne 0 ]; then 212 fail "ssh cert connect failed" 213 fi 214 215 # Revoked keys 216 verbose "$tid: ${_prefix} revoked key" 217 ( 218 cat $OBJ/sshd_proxy_bak 219 echo "RevokedKeys $OBJ/cert_user_key_revoked" 220 echo "PubkeyAcceptedAlgorithms ${t}" 221 echo "$extra_sshd" 222 ) > $OBJ/sshd_proxy 223 cp $OBJ/cert_user_key_${ktype}.pub \ 224 $OBJ/cert_user_key_revoked 225 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 226 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 227 if [ $? -eq 0 ]; then 228 fail "ssh cert connect succeeded unexpecedly" 229 fi 230 verbose "$tid: ${_prefix} revoked via KRL" 231 rm $OBJ/cert_user_key_revoked 232 ${SSHKEYGEN} -kqf $OBJ/cert_user_key_revoked \ 233 $OBJ/cert_user_key_${ktype}.pub 234 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 235 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 236 if [ $? -eq 0 ]; then 237 fail "ssh cert connect succeeded unexpecedly" 238 fi 239 verbose "$tid: ${_prefix} empty KRL" 240 ${SSHKEYGEN} -kqf $OBJ/cert_user_key_revoked 241 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 242 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 243 if [ $? -ne 0 ]; then 244 fail "ssh cert connect failed" 245 fi 246 done 247 248 # Revoked CA 249 verbose "$tid: ${ktype} $auth revoked CA key" 250 ( 251 cat $OBJ/sshd_proxy_bak 252 echo "RevokedKeys $OBJ/user_ca_key.pub" 253 echo "PubkeyAcceptedAlgorithms ${t}" 254 echo "$extra_sshd" 255 ) > $OBJ/sshd_proxy 256 ${SSH} -i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \ 257 somehost true >/dev/null 2>&1 258 if [ $? -eq 0 ]; then 259 fail "ssh cert connect succeeded unexpecedly" 260 fi 261 262 verbose "$tid: $auth CA does not authenticate" 263 ( 264 cat $OBJ/sshd_proxy_bak 265 echo "PubkeyAcceptedAlgorithms ${t}" 266 echo "$extra_sshd" 267 ) > $OBJ/sshd_proxy 268 verbose "$tid: ensure CA key does not authenticate user" 269 ${SSH} -i $OBJ/user_ca_key \ 270 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 271 if [ $? -eq 0 ]; then 272 fail "ssh cert connect with CA key succeeded unexpectedly" 273 fi 274} 275 276basic_tests authorized_keys 277basic_tests TrustedUserCAKeys 278 279test_one() { 280 ident=$1 281 result=$2 282 sign_opts=$3 283 auth_choice=$4 284 auth_opt=$5 285 286 if test "x$auth_choice" = "x" ; then 287 auth_choice="authorized_keys TrustedUserCAKeys" 288 fi 289 290 for auth in $auth_choice ; do 291 for ktype in $rsa ed25519 ; do 292 cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy 293 if test "x$auth" = "xauthorized_keys" ; then 294 # Add CA to authorized_keys 295 ( 296 printf "cert-authority${auth_opt} " 297 cat $OBJ/user_ca_key.pub 298 ) > $OBJ/authorized_keys_$USER 299 else 300 echo > $OBJ/authorized_keys_$USER 301 echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" \ 302 >> $OBJ/sshd_proxy 303 echo "PubkeyAcceptedAlgorithms ${t}*" \ 304 >> $OBJ/sshd_proxy 305 if test "x$auth_opt" != "x" ; then 306 echo $auth_opt >> $OBJ/sshd_proxy 307 fi 308 fi 309 310 verbose "$tid: $ident auth $auth expect $result $ktype" 311 ${SSHKEYGEN} -q -s $OBJ/user_ca_key \ 312 -I "regress user key for $USER" \ 313 $sign_opts $OBJ/cert_user_key_${ktype} || 314 fail "couldn't sign cert_user_key_${ktype}" 315 316 ${SSH} -i $OBJ/cert_user_key_${ktype} \ 317 -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1 318 rc=$? 319 if [ "x$result" = "xsuccess" ] ; then 320 if [ $rc -ne 0 ]; then 321 fail "$ident failed unexpectedly" 322 fi 323 else 324 if [ $rc -eq 0 ]; then 325 fail "$ident succeeded unexpectedly" 326 fi 327 fi 328 done 329 done 330} 331 332test_one "correct principal" success "-n ${USER}" 333test_one "host-certificate" failure "-n ${USER} -h" 334test_one "wrong principals" failure "-n foo" 335test_one "cert not yet valid" failure "-n ${USER} -V20300101:20320101" 336test_one "cert expired" failure "-n ${USER} -V19800101:19900101" 337test_one "cert valid interval" success "-n ${USER} -V-1w:+2w" 338test_one "wrong source-address" failure "-n ${USER} -Osource-address=10.0.0.0/8" 339test_one "force-command" failure "-n ${USER} -Oforce-command=false" 340 341# Behaviour is different here: TrustedUserCAKeys doesn't allow empty principals 342test_one "empty principals" success "" authorized_keys 343test_one "empty principals" failure "" TrustedUserCAKeys 344 345# Check explicitly-specified principals: an empty principals list in the cert 346# should always be refused. 347 348# AuthorizedPrincipalsFile 349rm -f $OBJ/authorized_keys_$USER 350echo mekmitasdigoat > $OBJ/authorized_principals_$USER 351test_one "AuthorizedPrincipalsFile principals" success "-n mekmitasdigoat" \ 352 TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" 353test_one "AuthorizedPrincipalsFile no principals" failure "" \ 354 TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u" 355 356# principals= key option 357rm -f $OBJ/authorized_principals_$USER 358test_one "principals key option principals" success "-n mekmitasdigoat" \ 359 authorized_keys ',principals="mekmitasdigoat"' 360test_one "principals key option no principals" failure "" \ 361 authorized_keys ',principals="mekmitasdigoat"' 362 363# command= options vs. force-command in key 364test_one "force-command match true" success \ 365 "-n ${USER} -Oforce-command=true" \ 366 authorized_keys ',command="true"' 367test_one "force-command match true" failure \ 368 "-n ${USER} -Oforce-command=false" \ 369 authorized_keys ',command="false"' 370test_one "force-command mismatch 1" failure \ 371 "-n ${USER} -Oforce-command=false" \ 372 authorized_keys ',command="true"' 373test_one "force-command mismatch 2" failure \ 374 "-n ${USER} -Oforce-command=true" \ 375 authorized_keys ',command="false"' 376 377# Wrong certificate 378cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy 379for ktype in $PLAIN_TYPES ; do 380 t=$(kname $ktype) 381 # Self-sign 382 ${SSHKEYGEN} -q -s $OBJ/cert_user_key_${ktype} -I \ 383 "regress user key for $USER" \ 384 -n $USER $OBJ/cert_user_key_${ktype} || 385 fatal "couldn't sign cert_user_key_${ktype}" 386 verbose "$tid: user ${ktype} connect wrong cert" 387 ${SSH} -i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \ 388 somehost true >/dev/null 2>&1 389 if [ $? -eq 0 ]; then 390 fail "ssh cert connect $ident succeeded unexpectedly" 391 fi 392done 393 394rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key* 395rm -f $OBJ/authorized_principals_$USER 396 397