tests-common-functions.in 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/bin/bash -ex
  2. # vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80:
  3. #
  4. # Copyright (c) 2019 Red Hat, Inc.
  5. # Author: Sergio Correia <scorreia@redhat.com>
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. . tang-common-test-functions
  21. error() {
  22. echo "${1}" >&2
  23. exit 1
  24. }
  25. skip_test() {
  26. echo "${1}" >&2
  27. exit 77
  28. }
  29. # We require cryptsetup >= 2.0.4 to fully support LUKSv2.
  30. # Support is determined at build time.
  31. luks2_supported() {
  32. return @OLD_CRYPTSETUP@
  33. }
  34. # We require cryptsetup >= 2.6.0 to fully support LUKSv2 addkey/open by token ID
  35. # Support is determined at build time.
  36. luks2_existing_token_id_supported() {
  37. return @OLD_CRYPTSETUP_EXISTING_TOKEN_ID@
  38. }
  39. # Creates a new LUKS1 or LUKS2 device to be used.
  40. new_device() {
  41. local LUKS="${1}"
  42. local DEV="${2}"
  43. local PASS="${3}"
  44. # Some builders fail if the cryptsetup steps are not ran as root, so let's
  45. # skip the test now if not running as root.
  46. if [ "$(id -u)" != 0 ]; then
  47. skip_test "WARNING: You must be root to run this test; test skipped."
  48. fi
  49. # Using a default password, if none has been provided.
  50. if [ -z "${PASS}" ]; then
  51. PASS="${DEFAULT_PASS}"
  52. fi
  53. local DEV_CACHED="${TMP}/${LUKS}.cached"
  54. # Let's reuse an existing device, if there is one.
  55. if [ -f "${DEV_CACHED}" ]; then
  56. echo "Reusing cached ${LUKS} device..."
  57. cp -f "${DEV_CACHED}" "${DEV}"
  58. return 0
  59. fi
  60. fallocate -l64M "${DEV}"
  61. cryptsetup luksFormat --type "${LUKS}" --pbkdf pbkdf2 \
  62. --pbkdf-force-iterations 1000 --key-size 512 --batch-mode \
  63. --force-password "${DEV}" <<< "${PASS}"
  64. # Caching the just-formatted device for possible reuse.
  65. cp -f "${DEV}" "${DEV_CACHED}"
  66. }
  67. # Creates a new LUKS1 or LUKS2 device to be used, using a keyfile.
  68. new_device_keyfile() {
  69. local LUKS="${1}"
  70. local DEV="${2}"
  71. local KEYFILE="${3}"
  72. # Some builders fail if the cryptsetup steps are not ran as root, so let's
  73. # skip the test now if not running as root.
  74. if [ "$(id -u)" != 0 ]; then
  75. skip_test "WARNING: You must be root to run this test; test skipped."
  76. fi
  77. if [[ -z "${KEYFILE}" ]] || [[ ! -f "${KEYFILE}" ]]; then
  78. error "Invalid keyfile (${KEYFILE})."
  79. fi
  80. fallocate -l64M "${DEV}"
  81. cryptsetup luksFormat --type "${LUKS}" --pbkdf pbkdf2 \
  82. --pbkdf-force-iterations 1000 --key-size 512 --batch-mode \
  83. "${DEV}" "${KEYFILE}"
  84. }
  85. pin_cfg_equal() {
  86. # Let's remove the single quotes from the pin configuration.
  87. local cfg1="${1//\'/}"
  88. local cfg2="${2//\'/}"
  89. # Now we sort and present them in compact form.
  90. local sorted_cfg1 sorted_cfg2
  91. sorted_cfg1="$(jq --compact-output --sort-keys . < <(echo -n "${cfg1}"))"
  92. sorted_cfg2="$(jq --compact-output --sort-keys . < <(echo -n "${cfg2}"))"
  93. # And we finally compare.
  94. if [ "${sorted_cfg1}" = "${sorted_cfg2}" ]; then
  95. return 0
  96. fi
  97. return 1
  98. }
  99. compare_luks_header() {
  100. DEV1="${1}"
  101. DEV2="${2}"
  102. TMP="${3}"
  103. cryptsetup luksHeaderBackup "${DEV1}" \
  104. --header-backup-file "${TMP}"/check-header1
  105. cryptsetup luksHeaderBackup "${DEV2}" \
  106. --header-backup-file "${TMP}"/check-header2
  107. local cs1 cs2
  108. cs1=$(cksum "${TMP}"/check-header1 | cut -d' ' -f 1)
  109. cs2=$(cksum "${TMP}"/check-header2 | cut -d' ' -f 1)
  110. rm -f "${TMP}"/check-header{1,2}
  111. if [ "${cs1}" == "${cs2}" ]; then
  112. return 0
  113. fi
  114. return 1
  115. }
  116. used_luks1_metadata_slots() {
  117. DEV="${1}"
  118. if ! luksmeta test -d "${DEV}"; then
  119. echo ""
  120. return 0
  121. fi
  122. local clevis_uuid="cb6e8904-81ff-40da-a84a-07ab9ab5715e"
  123. luksmeta show -d "${DEV}" \
  124. | sed -rn "s|^([0-9]+)\s+active\s+${clevis_uuid}$|\1|p" \
  125. | tr '\n' ' ' | sed 's/ $//'
  126. }
  127. used_luks2_metadata_slots() {
  128. DEV="${1}"
  129. cryptsetup luksDump "${DEV}" \
  130. | grep -E -A1 "^\s+[0-9]+:\s+clevis$" \
  131. | sed -rn 's|^\s+Keyslot:\s+([0-9]+)$|\1|p' | sort -n \
  132. | tr '\n' ' ' | sed 's/ $//'
  133. }
  134. used_luks2_metadata_tokens() {
  135. DEV="${1}"
  136. cryptsetup luksDump "${DEV}" \
  137. | grep -E -B1 "^\s+Keyslot:\s+[0-9]+$" \
  138. | sed -rn 's|^\s+([0-9]+): clevis|\1|p' \
  139. | tr '\n' ' ' | sed 's/ $//'
  140. }
  141. compare_luks1_metadata() {
  142. DEV1="${1}"
  143. DEV2="${2}"
  144. # If both are non-initialized, metadata is the same.
  145. ! luksmeta test -d "${DEV1}" && ! luksmeta test -d "${DEV2}" && return 0
  146. # Otherwise, metadata differ.
  147. ! luksmeta test -d "${DEV1}" && return 1
  148. ! luksmeta test -d "${DEV2}" && return 1
  149. local slt1 slt2
  150. slt1=$(used_luks1_metadata_slots "${DEV1}")
  151. slt2=$(used_luks1_metadata_slots "${DEV2}")
  152. if [ "${slt1}" != "${slt2}" ]; then
  153. echo "used slots did not match ($slt1) ($slt2)" >&2
  154. return 1
  155. fi
  156. local slt md1 md2
  157. for slt in ${slt1}; do
  158. md1="$(luksmeta load -d "${DEV}" -s "${slt}")"
  159. md2="$(luksmeta load -d "${DEV2}" -s "${slt}")"
  160. if [ "${md1}" != "${md2}" ]; then
  161. echo "metadata in slot ${slt} did not match" >&2
  162. return 1
  163. fi
  164. done
  165. return 0
  166. }
  167. compare_luks2_metadata() {
  168. DEV1="${1}"
  169. DEV2="${2}"
  170. local slt1 slt2
  171. slt1=$(used_luks2_metadata_slots "${DEV1}")
  172. slt2=$(used_luks2_metadata_slots "${DEV2}")
  173. if [ "${slt1}" != "${slt2}" ]; then
  174. echo "used slots did not match ($slt1) ($slt2)" >&2
  175. return 1
  176. fi
  177. local tkn1 tkn2
  178. tkn1=$(used_luks2_metadata_tokens "${DEV1}")
  179. tkn2=$(used_luks2_metadata_tokens "${DEV2}")
  180. if [ "${tkn1}" != "${tkn2}" ]; then
  181. echo "used tokens did not match ($tkn1) ($tkn2)" >&2
  182. return 1
  183. fi
  184. local tkn md1 md2
  185. for tkn in ${tkn1}; do
  186. md1="$(cryptsetup token export --token-id "${tkn}" "${DEV1}")"
  187. md2="$(cryptsetup token export --token-id "${tkn}" "${DEV2}")"
  188. if [ "${md1}" != "${md2}" ]; then
  189. echo "metadata in token ${tkn} did not match" >&2
  190. return 1
  191. fi
  192. done
  193. return 0
  194. }
  195. new_passphrase() {
  196. jose jwk gen --input='{"kty":"oct","bytes":8}' --output=- \
  197. | jose fmt --json=- --object --get k --unquote=-
  198. }
  199. export DEFAULT_PASS=' just-some- test-password-here 1.+?~!@#$%^&*();:'"'"'"[]{}_=/`\ '