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