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