fips_crypto_hmac.sh 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #!/bin/bash
  2. # fips_crypto_hmac.sh
  3. #
  4. # Author : Rohit Kothari (r.kothari@samsung.com)
  5. # Created on : 14 Feb 2014
  6. # Copyright (c) Samsung Electronics 2014
  7. # Given a vmlinux file and a System.map, this scripts finds bytes belonging to
  8. # Kernel Crypto within vmlinux file.(Under section .text, .init.text, .exit.text and .rodata)
  9. # After collecting all the bytes, it calculates a hmac(sha256) on those bytes.
  10. # Generated hmac is put back into a crypto rodata variable within vmlinux file itself.
  11. # This makes the build time hmac available at runtime, for integrity check.
  12. #
  13. # To find crypto bytes, this scripts heavily relies on output of arm-eabi-readelf.
  14. # If the output of arm-eabi-readelf changes in future, this script might need changes.
  15. #
  16. # Pre-conditions : $READELF, $HOSTCC variables are set.
  17. #
  18. #
  19. if test $# -ne 2; then
  20. echo "Usage: $0 vmlinux System.map"
  21. exit 1
  22. fi
  23. vmlinux_var=$1
  24. system_map_var=$2
  25. if [[ -z "$vmlinux_var" || -z "$system_map_var" || -z "$READELF" || -z "$HOSTCC" ]]; then
  26. echo "$0 : variables not set"
  27. exit 1
  28. fi
  29. if [[ ! -f $vmlinux_var || ! -f $system_map_var ]]; then
  30. echo "$0 : files does not exist"
  31. exit 1
  32. fi
  33. rm -f vmlinux.elf
  34. $READELF -S $vmlinux_var > vmlinux.elf
  35. retval=$?
  36. if [ $retval -ne 0 ]; then
  37. echo "$0 : $READELF returned error"
  38. exit 1
  39. fi
  40. declare -A array
  41. # FOR GENERIC CRYPTO FILES #awk fields to cut
  42. array[0]=".text first_crypto_text last_crypto_text \$5 \$6"
  43. array[1]=".rodata first_crypto_rodata last_crypto_rodata \$5 \$6"
  44. array[2]=".init.text first_crypto_init last_crypto_init \$4 \$5"
  45. array[3]=".exit.text first_crypto_exit last_crypto_exit \$4 \$5"
  46. # # FOR ASM CRYPTO FILES
  47. array[4]=".text first_crypto_asm_text last_crypto_asm_text \$5 \$6"
  48. array[5]=".rodata first_crypto_asm_rodata last_crypto_asm_rodata \$5 \$6"
  49. array[6]=".init.text first_crypto_asm_init last_crypto_asm_init \$4 \$5"
  50. array[7]=".exit.text first_crypto_asm_exit last_crypto_asm_exit \$4 \$5"
  51. rm -f offsets_sizes.txt
  52. #Addresses retrieved must be a valid hex
  53. reg='^[0-9A-Fa-f]+$'
  54. #Total bytes of all crypto sections scanned. Used later for error checking
  55. total_bytes=0;
  56. # For each type of Section :
  57. # first_addr = Address of first_crypto_text, first_crypto_rodata, etc.
  58. # last_addr = Address of last_crypto_text, last_crypto_rodata etc.
  59. # start_addr = Starting Address of a section within vmlinux
  60. # offset = Offset in vmlinux file where the section begins
  61. # file_offset = Offset in vmlinux file where the crypto bytes begins.
  62. # size = size of crypto bytes.
  63. # Output is offsets_sizes.txt, of the format
  64. # Section Name crypto_bytes_offset crypto_bytes_size
  65. # (in decimal) (in decimal)
  66. # .text 2531072 114576
  67. # .rodata 9289648 55388
  68. # : : :
  69. for i in "${array[@]}"; do
  70. var1=var2=var3=var4=var5=""
  71. first_addr=last_addr=start_addr=offset=file_offset=size=""
  72. k=1
  73. #This loop creates var1, var2 etc and set them to individual strings of a row in array
  74. for j in $i; do
  75. export var$k=$j
  76. let k+=1
  77. done
  78. first_addr=`cat $system_map_var|grep -w $var2|awk '{print $1}'`
  79. if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr invalid"; exit 1; fi
  80. last_addr=`cat $system_map_var|grep -w $var3|awk '{print $1}'`
  81. if [[ ! $last_addr =~ $reg ]]; then echo "$0 : last_addr invalid"; exit 1; fi
  82. start_addr=`cat vmlinux.elf |grep -w $var1|grep PROGBITS|awk '{print '$var4'}'`
  83. if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr invalid"; exit 1; fi
  84. offset=`cat vmlinux.elf |grep -w $var1|grep PROGBITS|awk '{print '$var5'}'`
  85. if [[ ! $offset =~ $reg ]]; then echo "$0 : offset invalid"; exit 1; fi
  86. if [[ $((16#$first_addr)) -lt $((16#$start_addr)) ]]; then echo "$0 : first_addr < start_addr"; exit 1; fi
  87. if [[ $((16#$last_addr)) -le $((16#$first_addr)) ]]; then echo "$0 : last_addr <= first_addr"; exit 1; fi
  88. file_offset=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr))`
  89. if [[ $file_offset -le 0 ]]; then echo "$0 : file_offset invalid"; exit 1; fi
  90. size=`expr $((16#$last_addr)) - $((16#$first_addr))`
  91. if [[ $size -le 0 ]]; then echo "$0 : crypto section size invalid"; exit 1; fi
  92. echo "$var1 " $file_offset " " $size >> offsets_sizes.txt
  93. let "total_bytes += `expr $((16#$last_addr)) - $((16#$first_addr))`"
  94. done
  95. if [[ ! -f offsets_sizes.txt ]]; then
  96. echo "$0 : offset_sizes.txt does not exist"
  97. exit 1
  98. fi
  99. rm -f fips_crypto_utils
  100. $HOSTCC -o fips_crypto_utils $srctree/scripts/fips_crypto_utils.c
  101. retval=$?
  102. if [ $retval -ne 0 ]; then
  103. echo "$0 : $HOSTCC returned error"
  104. exit 1
  105. fi
  106. rm -f builtime_bytes.txt #used for debugging
  107. rm -f builtime_bytes.bin #used for calculating hmac
  108. date_var=`date`
  109. echo "Created on : " $date_var > builtime_bytes.txt
  110. #Using offsets_sizes.txt, dump crypto bytes from vmlinux file into builtime_bytes.bin
  111. #Also gather printf's into builtime_bytes.txt, for debugging if required
  112. while read args; do
  113. ./fips_crypto_utils -g $vmlinux_var $args builtime_bytes.bin >> builtime_bytes.txt
  114. retval=$?
  115. if [ $retval -ne 0 ]; then
  116. echo "$0 : fips_crypto_utils : unable to gather crypto bytes from vmlinux"
  117. exit 1
  118. fi
  119. echo "" >> builtime_bytes.txt
  120. done < offsets_sizes.txt # <================== offsets_sizes.txt
  121. if [[ ! -f builtime_bytes.bin ]]; then
  122. echo "$0 : builtime_bytes.bin does not exist"
  123. exit 1
  124. fi
  125. file_size=`cat builtime_bytes.bin| wc -c`
  126. # Make sure that file size of crypto_hmac.bin is as expected
  127. if [ $total_bytes -ne $file_size ]; then
  128. echo "$0: Bytes mismatch"
  129. exit 1
  130. fi
  131. key="The quick brown fox jumps over the lazy dog"
  132. # Now, generate the hmac.
  133. openssl dgst -sha256 -hmac "$key" -binary -out crypto_hmac.bin builtime_bytes.bin
  134. retval=$?
  135. if [ $retval -ne 0 ]; then
  136. echo "$0 : openssl dgst command returned error"
  137. exit 1
  138. fi
  139. # Just, for debugging, print the same hmac on console
  140. openssl dgst -sha256 -hmac "$key" builtime_bytes.bin
  141. retval=$?
  142. if [ $retval -ne 0 ]; then
  143. echo "$0 : openssl dgst command returned error"
  144. exit 1
  145. fi
  146. if [[ ! -f crypto_hmac.bin ]]; then
  147. echo "$0 : crypto_hmac.bin does not exist"
  148. exit 1
  149. fi
  150. file_size=`cat crypto_hmac.bin| wc -c`
  151. # hmac(sha256) produces 32 bytes of hmac
  152. if [ $file_size -ne 32 ]; then
  153. echo "$0: Unexpected size of Hash file : " $file_size
  154. exit 1
  155. fi
  156. # Now that we have the hmac, update this hmac into an rodata "builtime_crypto_hmac" varialble
  157. # in vmlinux file.
  158. # This variable has a place holder 32 bytes that will be over-written with generated hmac.
  159. # This way, this build time hmac, will be available as a read-only variable at run-time.
  160. first_addr=`cat $system_map_var|grep -w "builtime_crypto_hmac"|awk '{print $1}' `
  161. if [[ ! $first_addr =~ $reg ]]; then echo "$0 : first_addr of hmac variable invalid"; exit 1; fi
  162. start_addr=`cat vmlinux.elf |grep -w ".rodata"|grep PROGBITS|awk '{print $5}' `
  163. if [[ ! $start_addr =~ $reg ]]; then echo "$0 : start_addr of .rodata invalid"; exit 1; fi
  164. offset=`cat vmlinux.elf |grep -w ".rodata"|grep PROGBITS| awk '{print $6}' `
  165. if [[ ! $offset =~ $reg ]]; then echo "$0 : offset of .rodata invalid"; exit 1; fi
  166. if [[ $((16#$first_addr)) -le $((16#$start_addr)) ]]; then echo "$0 : hmac var first_addr <= start_addr"; exit 1; fi
  167. hmac_offset=`expr $((16#$offset)) + $((16#$first_addr)) - $((16#$start_addr))`
  168. if [[ $hmac_offset -le 0 ]]; then echo "$0 : hmac_offset invalid"; exit 1; fi
  169. # This does the actual update of hmac into vmlinux file, at given offset
  170. ./fips_crypto_utils -u $vmlinux_var crypto_hmac.bin $hmac_offset
  171. retval=$?
  172. if [ $retval -ne 0 ]; then
  173. echo "$0 : fips_crypto_utils : unable to update hmac in vmlinux"
  174. exit 1
  175. fi
  176. rm -f crypto_hmac.bin
  177. rm -f builtime_bytes.txt
  178. rm -f builtime_bytes.bin
  179. rm -f fips_crypto_utils
  180. rm -f vmlinux.elf
  181. rm -f offsets_sizes.txt
  182. # And we are done...