cert-hostkey.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. # $OpenBSD: cert-hostkey.sh,v 1.23 2020/01/03 03:02:26 djm Exp $
  2. # Placed in the Public Domain.
  3. tid="certified host keys"
  4. rm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/host_revoked_*
  5. rm -f $OBJ/cert_host_key* $OBJ/host_krl_*
  6. # Allow all hostkey/pubkey types, prefer certs for the client
  7. rsa=0
  8. types=""
  9. for i in $($SSH -Q key | maybe_filter_sk); do
  10. if [ -z "$types" ]; then
  11. types="$i"
  12. continue
  13. fi
  14. case "$i" in
  15. # Special treatment for RSA keys.
  16. *rsa*cert*)
  17. types="rsa-sha2-256-cert-v01@openssh.com,$i,$types"
  18. types="rsa-sha2-512-cert-v01@openssh.com,$types"
  19. ;;
  20. *rsa*)
  21. rsa=1
  22. types="$types,rsa-sha2-512,rsa-sha2-256,$i"
  23. ;;
  24. # Prefer certificate to plain keys.
  25. *cert*) types="$i,$types" ;;
  26. *) types="$types,$i" ;;
  27. esac
  28. done
  29. (
  30. echo "HostKeyAlgorithms ${types}"
  31. echo "PubkeyAcceptedKeyAlgorithms *"
  32. ) >> $OBJ/ssh_proxy
  33. cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
  34. (
  35. echo "HostKeyAlgorithms *"
  36. echo "PubkeyAcceptedKeyAlgorithms *"
  37. ) >> $OBJ/sshd_proxy_bak
  38. HOSTS='localhost-with-alias,127.0.0.1,::1'
  39. kh_ca()
  40. {
  41. for k in "$@"; do
  42. printf "@cert-authority $HOSTS "
  43. cat $OBJ/$k || fatal "couldn't cat $k"
  44. done
  45. }
  46. kh_revoke()
  47. {
  48. for k in "$@"; do
  49. printf "@revoked * "
  50. cat $OBJ/$k || fatal "couldn't cat $k"
  51. done
  52. }
  53. # Create a CA key and add it to known hosts. Ed25519 chosen for speed.
  54. # RSA for testing RSA/SHA2 signatures if supported.
  55. ktype2=ed25519
  56. [ "x$rsa" = "x1" ] && ktype2=rsa
  57. ${SSHKEYGEN} -q -N '' -t ed25519 -f $OBJ/host_ca_key ||
  58. fail "ssh-keygen of host_ca_key failed"
  59. ${SSHKEYGEN} -q -N '' -t $ktype2 -f $OBJ/host_ca_key2 ||
  60. fail "ssh-keygen of host_ca_key failed"
  61. kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
  62. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  63. # Plain text revocation files
  64. touch $OBJ/host_revoked_empty
  65. touch $OBJ/host_revoked_plain
  66. touch $OBJ/host_revoked_cert
  67. cat $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub > $OBJ/host_revoked_ca
  68. PLAIN_TYPES=$(echo "$SSH_KEYTYPES" | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//')
  69. if echo "$PLAIN_TYPES" | grep '^rsa$' > /dev/null 2>&1; then
  70. PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512"
  71. fi
  72. # Prepare certificate, plain key and CA KRLs
  73. ${SSHKEYGEN} -kf $OBJ/host_krl_empty || fatal "KRL init failed"
  74. ${SSHKEYGEN} -kf $OBJ/host_krl_plain || fatal "KRL init failed"
  75. ${SSHKEYGEN} -kf $OBJ/host_krl_cert || fatal "KRL init failed"
  76. ${SSHKEYGEN} -kf $OBJ/host_krl_ca $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub ||
  77. fatal "KRL init failed"
  78. # Generate and sign host keys
  79. serial=1
  80. for ktype in $PLAIN_TYPES; do
  81. verbose "$tid: sign host ${ktype} cert"
  82. # Generate and sign a host key
  83. ${SSHKEYGEN} -q -N '' -t ${ktype} \
  84. -f $OBJ/cert_host_key_${ktype} ||
  85. fatal "ssh-keygen of cert_host_key_${ktype} failed"
  86. ${SSHKEYGEN} -ukf $OBJ/host_krl_plain \
  87. $OBJ/cert_host_key_${ktype}.pub || fatal "KRL update failed"
  88. cat $OBJ/cert_host_key_${ktype}.pub >> $OBJ/host_revoked_plain
  89. case $ktype in
  90. rsa-sha2-*)
  91. tflag="-t $ktype"
  92. ca="$OBJ/host_ca_key2"
  93. ;;
  94. *)
  95. tflag=""
  96. ca="$OBJ/host_ca_key"
  97. ;;
  98. esac
  99. ${SSHKEYGEN} -h -q -s $ca -z $serial $tflag \
  100. -I "regress host key for $USER" \
  101. -n $HOSTS $OBJ/cert_host_key_${ktype} ||
  102. fatal "couldn't sign cert_host_key_${ktype}"
  103. ${SSHKEYGEN} -ukf $OBJ/host_krl_cert \
  104. $OBJ/cert_host_key_${ktype}-cert.pub ||
  105. fatal "KRL update failed"
  106. cat $OBJ/cert_host_key_${ktype}-cert.pub >> $OBJ/host_revoked_cert
  107. serial=$(expr $serial + 1)
  108. done
  109. attempt_connect()
  110. {
  111. _ident="$1"
  112. _expect_success="$2"
  113. shift
  114. shift
  115. verbose "$tid: $_ident expect success $_expect_success"
  116. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  117. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  118. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  119. "$@" -F $OBJ/ssh_proxy somehost true
  120. _r=$?
  121. if [ "x$_expect_success" = "xyes" ]; then
  122. if [ $_r -ne 0 ]; then
  123. fail "ssh cert connect $_ident failed"
  124. fi
  125. else
  126. if [ $_r -eq 0 ]; then
  127. fail "ssh cert connect $_ident succeeded unexpectedly"
  128. fi
  129. fi
  130. }
  131. # Basic connect and revocation tests.
  132. for privsep in yes; do
  133. for ktype in $PLAIN_TYPES; do
  134. verbose "$tid: host ${ktype} cert connect privsep $privsep"
  135. (
  136. cat $OBJ/sshd_proxy_bak
  137. echo HostKey $OBJ/cert_host_key_${ktype}
  138. echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
  139. echo UsePrivilegeSeparation $privsep
  140. ) > $OBJ/sshd_proxy
  141. # test name expect success
  142. attempt_connect "$ktype basic connect" "yes"
  143. attempt_connect "$ktype empty KRL" "yes" \
  144. -oRevokedHostKeys=$OBJ/host_krl_empty
  145. attempt_connect "$ktype KRL w/ plain key revoked" "no" \
  146. -oRevokedHostKeys=$OBJ/host_krl_plain
  147. attempt_connect "$ktype KRL w/ cert revoked" "no" \
  148. -oRevokedHostKeys=$OBJ/host_krl_cert
  149. attempt_connect "$ktype KRL w/ CA revoked" "no" \
  150. -oRevokedHostKeys=$OBJ/host_krl_ca
  151. attempt_connect "$ktype empty plaintext revocation" "yes" \
  152. -oRevokedHostKeys=$OBJ/host_revoked_empty
  153. attempt_connect "$ktype plain key plaintext revocation" "no" \
  154. -oRevokedHostKeys=$OBJ/host_revoked_plain
  155. attempt_connect "$ktype cert plaintext revocation" "no" \
  156. -oRevokedHostKeys=$OBJ/host_revoked_cert
  157. attempt_connect "$ktype CA plaintext revocation" "no" \
  158. -oRevokedHostKeys=$OBJ/host_revoked_ca
  159. done
  160. done
  161. # Revoked certificates with key present
  162. kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
  163. for ktype in $PLAIN_TYPES; do
  164. test -f "$OBJ/cert_host_key_${ktype}.pub" || fatal "no pubkey"
  165. kh_revoke cert_host_key_${ktype}.pub >> $OBJ/known_hosts-cert.orig
  166. done
  167. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  168. for privsep in yes; do
  169. for ktype in $PLAIN_TYPES; do
  170. verbose "$tid: host ${ktype} revoked cert privsep $privsep"
  171. (
  172. cat $OBJ/sshd_proxy_bak
  173. echo HostKey $OBJ/cert_host_key_${ktype}
  174. echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
  175. echo UsePrivilegeSeparation $privsep
  176. ) > $OBJ/sshd_proxy
  177. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  178. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  179. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  180. -F $OBJ/ssh_proxy somehost true > /dev/null 2>&1
  181. if [ $? -eq 0 ]; then
  182. fail "ssh cert connect succeeded unexpectedly"
  183. fi
  184. done
  185. done
  186. # Revoked CA
  187. kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
  188. kh_revoke host_ca_key.pub host_ca_key2.pub >> $OBJ/known_hosts-cert.orig
  189. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  190. for ktype in $PLAIN_TYPES; do
  191. verbose "$tid: host ${ktype} revoked cert"
  192. (
  193. cat $OBJ/sshd_proxy_bak
  194. echo HostKey $OBJ/cert_host_key_${ktype}
  195. echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
  196. ) > $OBJ/sshd_proxy
  197. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  198. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  199. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  200. -F $OBJ/ssh_proxy somehost true > /dev/null 2>&1
  201. if [ $? -eq 0 ]; then
  202. fail "ssh cert connect succeeded unexpectedly"
  203. fi
  204. done
  205. # Create a CA key and add it to known hosts
  206. kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
  207. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  208. test_one()
  209. {
  210. ident=$1
  211. result=$2
  212. sign_opts=$3
  213. for kt in $PLAIN_TYPES; do
  214. case $ktype in
  215. rsa-sha2-*)
  216. tflag="-t $ktype"
  217. ca="$OBJ/host_ca_key2"
  218. ;;
  219. *)
  220. tflag=""
  221. ca="$OBJ/host_ca_key"
  222. ;;
  223. esac
  224. ${SSHKEYGEN} -q -s $ca $tflag -I "regress host key for $USER" \
  225. $sign_opts $OBJ/cert_host_key_${kt} ||
  226. fatal "couldn't sign cert_host_key_${kt}"
  227. (
  228. cat $OBJ/sshd_proxy_bak
  229. echo HostKey $OBJ/cert_host_key_${kt}
  230. echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
  231. ) > $OBJ/sshd_proxy
  232. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  233. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  234. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  235. -F $OBJ/ssh_proxy somehost true > /dev/null 2>&1
  236. rc=$?
  237. if [ "x$result" = "xsuccess" ]; then
  238. if [ $rc -ne 0 ]; then
  239. fail "ssh cert connect $ident failed unexpectedly"
  240. fi
  241. else
  242. if [ $rc -eq 0 ]; then
  243. fail "ssh cert connect $ident succeeded unexpectedly"
  244. fi
  245. fi
  246. done
  247. }
  248. test_one "user-certificate" failure "-n $HOSTS"
  249. test_one "empty principals" success "-h"
  250. test_one "wrong principals" failure "-h -n foo"
  251. test_one "cert not yet valid" failure "-h -V20300101:20320101"
  252. test_one "cert expired" failure "-h -V19800101:19900101"
  253. test_one "cert valid interval" success "-h -V-1w:+2w"
  254. test_one "cert has constraints" failure "-h -Oforce-command=false"
  255. # Check downgrade of cert to raw key when no CA found
  256. for ktype in $PLAIN_TYPES; do
  257. rm -f $OBJ/known_hosts-cert $OBJ/cert_host_key*
  258. verbose "$tid: host ${ktype} ${v} cert downgrade to raw key"
  259. # Generate and sign a host key
  260. ${SSHKEYGEN} -q -N '' -t ${ktype} -f $OBJ/cert_host_key_${ktype} ||
  261. fail "ssh-keygen of cert_host_key_${ktype} failed"
  262. case $ktype in
  263. rsa-sha2-*)
  264. tflag="-t $ktype"
  265. ca="$OBJ/host_ca_key2"
  266. ;;
  267. *)
  268. tflag=""
  269. ca="$OBJ/host_ca_key"
  270. ;;
  271. esac
  272. ${SSHKEYGEN} -h -q $tflag -s $ca $tflag \
  273. -I "regress host key for $USER" \
  274. -n $HOSTS $OBJ/cert_host_key_${ktype} ||
  275. fatal "couldn't sign cert_host_key_${ktype}"
  276. (
  277. printf "$HOSTS "
  278. cat $OBJ/cert_host_key_${ktype}.pub
  279. ) > $OBJ/known_hosts-cert
  280. (
  281. cat $OBJ/sshd_proxy_bak
  282. echo HostKey $OBJ/cert_host_key_${ktype}
  283. echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
  284. ) > $OBJ/sshd_proxy
  285. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  286. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  287. -F $OBJ/ssh_proxy somehost true
  288. if [ $? -ne 0 ]; then
  289. fail "ssh cert connect failed"
  290. fi
  291. done
  292. # Wrong certificate
  293. kh_ca host_ca_key.pub host_ca_key2.pub > $OBJ/known_hosts-cert.orig
  294. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  295. for kt in $PLAIN_TYPES; do
  296. verbose "$tid: host ${kt} connect wrong cert"
  297. rm -f $OBJ/cert_host_key*
  298. # Self-sign key
  299. ${SSHKEYGEN} -q -N '' -t ${kt} -f $OBJ/cert_host_key_${kt} ||
  300. fail "ssh-keygen of cert_host_key_${kt} failed"
  301. case $kt in
  302. rsa-sha2-*) tflag="-t $kt" ;;
  303. *) tflag="" ;;
  304. esac
  305. ${SSHKEYGEN} $tflag -h -q -s $OBJ/cert_host_key_${kt} \
  306. -I "regress host key for $USER" \
  307. -n $HOSTS $OBJ/cert_host_key_${kt} ||
  308. fatal "couldn't sign cert_host_key_${kt}"
  309. (
  310. cat $OBJ/sshd_proxy_bak
  311. echo HostKey $OBJ/cert_host_key_${kt}
  312. echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
  313. ) > $OBJ/sshd_proxy
  314. cp $OBJ/known_hosts-cert.orig $OBJ/known_hosts-cert
  315. ${SSH} -oUserKnownHostsFile=$OBJ/known_hosts-cert \
  316. -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
  317. -F $OBJ/ssh_proxy -q somehost true > /dev/null 2>&1
  318. if [ $? -eq 0 ]; then
  319. fail "ssh cert connect $ident succeeded unexpectedly"
  320. fi
  321. done
  322. rm -f $OBJ/known_hosts-cert* $OBJ/host_ca_key* $OBJ/cert_host_key*