sign.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # SPDX-License-Identifier: BSD-3-Clause
  2. source helpers.sh
  3. file_primary_key_ctx=context.p_B1
  4. file_signing_key_pub=opuB1_B8
  5. file_signing_key_priv=oprB1_B8
  6. file_signing_key_ctx=context_load_out_B1_B8
  7. file_signing_key_name=name.load.B1_B8
  8. file_signing_key_pub_pem=oppB1_B8
  9. file_input_data=secret.data
  10. file_input_digest=secret.digest
  11. file_output_data=sig.4
  12. file_output_ticket=secret.ticket
  13. file_output_hash=secret.hash
  14. rsa_key_type=rsa2048
  15. ecc_key_type=ecc256
  16. handle_signing_key=0x81010005
  17. alg_hash=sha256
  18. alg_primary_key=rsa
  19. cleanup() {
  20. rm -f $file_input_data $file_primary_key_ctx $file_signing_key_pub \
  21. $file_signing_key_priv $file_signing_key_ctx $file_signing_key_name \
  22. $file_output_data $file_input_digest $file_output_ticket \
  23. $file_output_hash $file_signing_key_pub_pem
  24. tpm2 evictcontrol -Q -Co -c $handle_signing_key 2>/dev/null || true
  25. if [ "$1" != "no-shut-down" ]; then
  26. shut_down
  27. fi
  28. }
  29. trap cleanup EXIT
  30. test_symmetric() {
  31. local alg_signing_key=$1
  32. echo "12345678" > $file_input_data
  33. tpm2 clear
  34. tpm2 createprimary -Q -C e -g $alg_hash -G $alg_primary_key \
  35. -c $file_primary_key_ctx
  36. tpm2 create -Q -g $alg_hash -G $alg_signing_key -u $file_signing_key_pub \
  37. -r $file_signing_key_priv -C $file_primary_key_ctx
  38. tpm2 load -Q -C $file_primary_key_ctx -u $file_signing_key_pub \
  39. -r $file_signing_key_priv -n $file_signing_key_name -c $file_signing_key_ctx
  40. tpm2 sign -Q -c $file_signing_key_ctx -g $alg_hash \
  41. -o $file_output_data $file_input_data
  42. rm -f $file_output_data
  43. tpm2 evictcontrol -Q -C o -c $file_signing_key_ctx $handle_signing_key
  44. tpm2 sign -Q -c $handle_signing_key -g $alg_hash -o $file_output_data \
  45. $file_input_data
  46. rm -f $file_output_data
  47. # generate hash and test validation
  48. tpm2 hash -Q -C e -g $alg_hash -o $file_output_hash -t $file_output_ticket \
  49. $file_input_data
  50. tpm2 sign -Q -c $handle_signing_key -g $alg_hash -o $file_output_data \
  51. -t $file_output_ticket $file_input_data
  52. rm -f $file_output_data
  53. # test with digest, no validation
  54. shasum -a 256 $file_input_data | awk '{ print "000000 " $1 }' | xxd -r -c 32 > \
  55. $file_input_digest
  56. tpm2 sign -Q -c $handle_signing_key -g $alg_hash -d -o $file_output_data \
  57. $file_input_digest
  58. rm -f $file_output_data
  59. }
  60. create_signature() {
  61. local sign_scheme=$1
  62. if [ "$sign_scheme" = "" ]; then
  63. tpm2 sign -Q -c $file_signing_key_ctx -g $alg_hash -f plain \
  64. -o $file_output_data $file_input_data
  65. else
  66. tpm2 sign -Q -c $file_signing_key_ctx -g $alg_hash -s $sign_scheme \
  67. -f plain -o $file_output_data $file_input_data
  68. fi
  69. }
  70. get_openssl_version_number() {
  71. # Ubuntu 14.04, 16.04, 18.04 and 19.04:
  72. # "OpenSSL 1.0.1f 6 Jan 2014"
  73. # "OpenSSL 1.0.2g 1 Mar 2016"
  74. # "OpenSSL 1.1.0g 2 Nov 2017"
  75. # "OpenSSL 1.1.1b 26 Feb 2019"
  76. if [ -z "$1" ]; then
  77. local openssl_version=$(openssl version -v)
  78. else
  79. local openssl_version="$1"
  80. fi
  81. local openssl_version_parsed=$(echo "$openssl_version" | sed -r 's/^OpenSSL ([0-9]+)\.([0-9]+)\.([0-9]+).*$/\1 \2 \3/')
  82. local openssl_v1=$(echo $openssl_version_parsed | cut -d ' ' -f 1)
  83. local openssl_v2=$(echo $openssl_version_parsed | cut -d ' ' -f 2)
  84. local openssl_v3=$(echo $openssl_version_parsed | cut -d ' ' -f 3)
  85. local openssl_version_num=$(("$openssl_v1"<<16 + "$openssl_v2"<<8 + "$openssl_v3"))
  86. echo "$openssl_version_num"
  87. }
  88. verify_signature() {
  89. local sign_scheme=$1
  90. if [ "$sign_scheme" = "rsapss" ] ; then
  91. # Explanation:
  92. # RSA-PSS has a parameter called salt length.
  93. # You need to know what value of salt length was used to create the
  94. # signature in order to verify the signature.
  95. # OpenSSL can actually automatically determine the correct value, so
  96. # strictly speaking we could just let it and simplify this test a lot.
  97. # But, if you want to verify the signature using some other API,
  98. # you might need to know the salt length used by the TPM to produce the
  99. # signature.
  100. # It can be either "digest" or "max". You can use openssl the check
  101. # whether it's "digest", and if it's not then it's "max".
  102. # From TCG TPM 2.0, Part 1: Architecture, Appendix B.7
  103. # "... the random salt length will be the largest size allowed by the
  104. # key size and message digest size."
  105. # From NIST FIPS PUB 186-4, Section 5.5
  106. # "... the length (in bytes) of the salt (sLen) shall satisfy
  107. # 0 <= sLen <= hLen, where hLen is the length of the hash function
  108. # output block (in bytes)."
  109. # From TCG FIPS 140-2 Guidance for TPM 2.0, Section 5.2.1.3
  110. # "If the TPM implementation is required to be compliant with FIPS 186-4,
  111. # then the random salt length will be the largest size allowed by that
  112. # specification."
  113. # Thus, if the TPM is in "FIPS mode", PSS salt length is "digest",
  114. # otherwise PSS salt length is "max".
  115. # Either one is accepted by this test.
  116. # The IBM TPM software emulator (at least the version in ibmtpm1332.tar.gz)
  117. # uses "digest".
  118. local openssl_current_version_num=$(get_openssl_version_number)
  119. local openssl_1_1_1_version_num=$(get_openssl_version_number "OpenSSL 1.1.1")
  120. # Explanation:
  121. # In version 1.1.1, openssl switched from "-1","-2" (meaning "digest" and
  122. # "auto" correspondingly) to "digest", "max" and "auto".
  123. # See section "rsa_pss_saltlen:len" in
  124. # https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/doc/man1/pkeyutl.pod
  125. # and same section in
  126. # https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/doc/apps/pkeyutl.pod
  127. if [ "$openssl_current_version_num" -ge "$openssl_1_1_1_version_num" ] ; then
  128. local pss_salt_len_arg_digest="digest"
  129. local pss_salt_len_arg_max="max"
  130. local pss_salt_len_arg_auto="auto"
  131. else
  132. local pss_salt_len_arg_digest="-1"
  133. local pss_salt_len_arg_auto="-2"
  134. fi
  135. openssl pkeyutl -verify \
  136. -in $file_input_digest \
  137. -sigfile $file_output_data \
  138. -pubin \
  139. -inkey $file_signing_key_pub_pem \
  140. -keyform pem \
  141. -pkeyopt digest:$alg_hash \
  142. -pkeyopt rsa_padding_mode:pss \
  143. -pkeyopt rsa_pss_saltlen:$pss_salt_len_arg_digest \
  144. |& grep -q '^Signature Verified Successfully' \
  145. || \
  146. openssl pkeyutl -verify \
  147. -in $file_input_digest \
  148. -sigfile $file_output_data \
  149. -pubin \
  150. -inkey $file_signing_key_pub_pem \
  151. -keyform pem \
  152. -pkeyopt digest:$alg_hash \
  153. -pkeyopt rsa_padding_mode:pss \
  154. -pkeyopt rsa_pss_saltlen:$pss_salt_len_arg_auto \
  155. |& grep -q '^Signature Verified Successfully'
  156. else
  157. openssl pkeyutl -verify \
  158. -in $file_input_digest \
  159. -sigfile $file_output_data \
  160. -pubin \
  161. -inkey $file_signing_key_pub_pem \
  162. -keyform pem \
  163. -pkeyopt digest:$alg_hash \
  164. |& grep -q '^Signature Verified Successfully'
  165. fi
  166. }
  167. test_asymmetric() {
  168. local alg_signing_key=$1
  169. head -c30 /dev/urandom > $file_input_data
  170. shasum -a 256 $file_input_data | awk '{ print "000000 " $1 }' | \
  171. xxd -r -c 32 > $file_input_digest
  172. tpm2 clear
  173. tpm2 createprimary -Q -C e -g $alg_hash -G $alg_primary_key \
  174. -c $file_primary_key_ctx
  175. tpm2 create -Q -g $alg_hash -G $alg_signing_key -u $file_signing_key_pub \
  176. -r $file_signing_key_priv -C $file_primary_key_ctx
  177. tpm2 load -Q -C $file_primary_key_ctx -u $file_signing_key_pub \
  178. -r $file_signing_key_priv -n $file_signing_key_name -c $file_signing_key_ctx
  179. tpm2 readpublic -Q -c $file_signing_key_ctx --format=pem \
  180. -o $file_signing_key_pub_pem
  181. local sign_scheme
  182. if [ "$alg_signing_key" = "$rsa_key_type" ] ; then
  183. for sign_scheme in "" "rsassa" "rsapss"
  184. do
  185. create_signature $sign_scheme
  186. verify_signature $sign_scheme
  187. rm -f $file_output_data
  188. done
  189. fi
  190. if [ "$alg_signing_key" = "$ecc_key_type" ]; then
  191. for sign_scheme in "" "ecdsa"
  192. do
  193. create_signature $sign_scheme
  194. verify_signature $sign_scheme
  195. rm -f $file_output_data
  196. done
  197. fi
  198. }
  199. start_up
  200. cleanup "no-shut-down"
  201. # make sure commands failing inside the function will cause the script to fail!
  202. (
  203. set -e
  204. test_symmetric "hmac"
  205. cleanup "no-shut-down"
  206. )
  207. for key_type in $rsa_key_type $ecc_key_type
  208. do
  209. # make sure commands failing inside the function will cause the script
  210. # to fail!
  211. (
  212. set -e
  213. test_asymmetric $key_type
  214. cleanup "no-shut-down"
  215. )
  216. done
  217. # Test signing with ecdaa scheme
  218. head -c30 /dev/urandom | openssl dgst -sha256 -binary > test.rnd
  219. tpm2 clear
  220. tpm2 createprimary -Q -C o -c prim.ctx -g sha256 -G rsa
  221. tpm2 create -Q -g sha256 -G ecc256:ecdaa -u key.pub -r key.priv -C prim.ctx
  222. tpm2 load -C prim.ctx -u key.pub -r key.priv -n key.name -c key.ctx
  223. tpm2 readpublic -c key.ctx --format=pem -o key.pem
  224. tpm2 commit -c key.ctx -t commit.ctr --eccpoint-K K.bin --eccpoint-L L.bin -u E.bin
  225. tpm2 commit -c key.ctx -t commit.ctr --eccpoint-K K.bin --eccpoint-L L.bin -u E.bin
  226. tpm2 sign -c key.ctx -g sha256 -o test.sig test.rnd -s ecdaa --commit-index 1
  227. tpm2 sign -c key.ctx -g sha256 -o test.sig test.rnd -s ecdaa
  228. # Test that invalid password returns the proper code
  229. cleanup "no-shut-down"
  230. echo "12345678" > $file_input_data
  231. tpm2 createprimary -Q -c $file_primary_key_ctx
  232. tpm2 create -Q -C $file_primary_key_ctx -u $file_signing_key_pub \
  233. -r $file_signing_key_priv -p "mypassword"
  234. tpm2 load -Q -C $file_primary_key_ctx -u $file_signing_key_pub \
  235. -r $file_signing_key_priv -n $file_signing_key_name -c $file_signing_key_ctx
  236. # Negative test, remove error handler
  237. trap - ERR
  238. tpm2 sign -Q -p "badpassword" -c $file_signing_key_ctx -g $alg_hash \
  239. -o $file_output_data $file_input_data
  240. if [ $? != 3]; then
  241. echo "Expected RC 3, got: $?" 1>&2
  242. fi
  243. trap onerror ERR
  244. exit 0