cert-userkey.sh 12 KB

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