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