4 [ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".."
5 CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup
6 CRYPTSETUP_RAW=$CRYPTSETUP
8 CRYPTSETUP_VALGRIND=../.libs/cryptsetup
9 CRYPTSETUP_LIB_VALGRIND=../.libs
16 FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
17 CS_PWPARAMS="--disable-keyring --key-file $KEY1"
18 CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
21 function remove_mapping()
23 [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
24 rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1
30 [ -n "$1" ] && echo "$1"
31 echo "FAILED backtrace:"
32 while caller $frame; do ((frame++)); done
39 [ -n "$1" ] && echo "$1"
46 which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped."
49 function img_json_save()
51 # FIXME: why --json-file cannot be used?
52 #$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M | tr -d '\n' >$IMG_JSON
53 local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
54 _dd if=$IMG count=$LUKS2_JSON_SIZE skip=4096 | jq -c -M . | tr -d '\n' >$IMG_JSON
57 function img_json_dump()
63 function img_hash_save()
65 IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
68 function img_hash_unchanged()
70 local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
71 [ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
74 function img_prepare_raw() # $1 options
78 if [ ! -e $KEY1 ]; then
79 dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
82 truncate -s 32M $IMG || fail
83 $CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
86 function img_prepare() # $1 options
89 # FIXME: resilience is not saved here (always none)?
90 $CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1
91 [ $? -ne 0 ] && skip "Reencryption unsupported, test skipped."
98 dd $@ status=none conv=notrunc bs=1
101 # header mangle functions
102 function img_update_json()
104 local LUKS2_BIN1_OFFSET=448
105 local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
106 local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
108 # if present jq script, mangle JSON
110 local JSON=$(cat $IMG_JSON)
111 echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
112 local JSON=$(cat $IMG_JSON)
113 echo $JSON | tr -d '\n' >$IMG_JSON || fail
117 _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096
118 _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
121 _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096
122 _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
124 # erase sha256 checksums
125 _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET
126 _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET
128 # calculate sha256 and write chexksums
129 local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
130 echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail
132 local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
133 echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail
138 function img_check_ok()
140 if [ $(id -u) == 0 ]; then
141 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
142 $CRYPTSETUP close $DEV_NAME || fail
145 $CRYPTSETUP repair $IMG $CS_PARAMS || fail
148 function img_check_fail()
150 if [ $(id -u) == 0 ]; then
151 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
154 $CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
158 function img_run_reenc_ok()
160 local EXPECT_TIMEOUT=5
161 [ -n "$VALG" ] && EXPECT_TIMEOUT=60
162 # For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
163 expect_run - >/dev/null <<EOF
164 proc abort {} { send_error "Timeout. "; exit 2 }
165 set timeout $EXPECT_TIMEOUT
166 eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks --resilience none
167 expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
169 expect timeout abort eof
172 [ $? -eq 0 ] || fail "Expect script failed."
175 function img_run_reenc_fail()
177 local EXPECT_TIMEOUT=5
178 [ -n "$VALG" ] && EXPECT_TIMEOUT=60
179 # For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here.
180 expect_run - >/dev/null <<EOF
181 proc abort {} { send_error "Timeout. "; exit 42 }
182 set timeout $EXPECT_TIMEOUT
183 eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
184 expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
186 expect timeout abort eof
188 exit [lindex \$result 3]
191 [ $ret -eq 0 ] && fail "Reencryption passed (should have failed)."
192 [ $ret -eq 42 ] && fail "Expect script failed."
196 function img_check_fail_repair_ok()
198 if [ $(id -u) == 0 ]; then
199 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
205 $CRYPTSETUP repair $IMG $CS_PARAMS || fail
211 function valgrind_setup()
214 [ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
215 export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
216 CRYPTSETUP=valgrind_run
217 CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
220 function valgrind_run()
222 INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
225 function expect_run()
227 export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
238 [ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
242 echo "[1] Reencryption with old flag is rejected"
244 img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
246 img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
251 # Simulate old reencryption with no digest (repairable)
253 img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
254 img_check_fail_repair_ok
256 # This must fail for new releases
257 echo "[2] Old reencryption in-progress (journal)"
261 .keyslots."2".area.type = "journal" |
263 "0" : (.segments."0" +
264 {"size" : .keyslots."2".area.size} +
265 {"flags" : ["in-reencryption"]}),
266 "1" : (.segments."0" +
267 {"offset" : ((.segments."0".offset|tonumber) +
268 (.keyslots."2".area.size|tonumber))|tostring}),
272 .digests."0".segments = ["1","2"] |
273 .digests."1".segments = ["0","3"] |
274 .config.requirements.mandatory = ["online-reencrypt"]'
275 img_check_fail_repair_ok
277 echo "[3] Old reencryption in-progress (checksum)"
281 .keyslots."2".area.type = "checksum" |
282 .keyslots."2".area.hash = "sha256" |
283 .keyslots."2".area.sector_size = 4096 |
285 "0" : (.segments."0" +
286 {"size" : .keyslots."2".area.size} +
287 {"flags" : ["in-reencryption"]}),
288 "1" : (.segments."0" +
289 {"offset": ((.segments."0".offset|tonumber) +
290 (.keyslots."2".area.size|tonumber))|tostring}),
294 .digests."0".segments = ["1","2"] |
295 .digests."1".segments = ["0","3"] |
296 .config.requirements.mandatory = ["online-reencrypt"]'
297 img_check_fail_repair_ok
299 # Note: older tools cannot create this from commandline
300 echo "[4] Old decryption in-progress (journal)"
306 .keyslots."2".mode = "decrypt" |
307 .keyslots."2".area.type = "journal" |
311 "offset" : .segments."0".offset,
312 "size" : .keyslots."2".area.size,
313 "flags" : ["in-reencryption"]
315 "1" : (.segments."0" +
316 {"offset" : ((.segments."0".offset|tonumber) +
317 (.keyslots."2".area.size|tonumber))|tostring}),
321 "offset" : .segments."0".offset,
323 "flags" : ["backup-final"]
326 .digests."0".segments = ["1","2"] |
327 .config.requirements.mandatory = ["online-reencrypt"]'
328 img_check_fail_repair_ok
330 echo "[5] Old decryption in-progress (checksum)"
336 .keyslots."2".mode = "decrypt" |
337 .keyslots."2".area.type = "checksum" |
338 .keyslots."2".area.hash = "sha256" |
339 .keyslots."2".area.sector_size = 4096 |
343 "offset" : .segments."0".offset,
344 "size" : .keyslots."2".area.size,
345 "flags" : ["in-reencryption"]
347 "1" : (.segments."0" +
348 {"offset" : ((.segments."0".offset|tonumber) +
349 (.keyslots."2".area.size|tonumber))|tostring}),
353 "offset" : .segments."0".offset,
355 "flags" : ["backup-final"]
358 .digests."0".segments = ["1","2"] |
359 .config.requirements.mandatory = ["online-reencrypt"]'
360 img_check_fail_repair_ok
362 # Note - offset is set to work with the old version (with a datashift bug)
363 echo "[6] Old reencryption in-progress (datashift)"
367 .keyslots."2".direction = "backward" |
368 .keyslots."2".area.type = "datashift" |
369 .keyslots."2".area.size = "4096" |
370 .keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
372 "0" : (.segments."0" +
373 {"size" : ((13 * 1024 * 1024)|tostring)}),
374 "1" : (.segments."0" +
375 {"offset" : ((30 * 1024 * 1024)|tostring)}),
377 "3" : (.segments."2" +
378 {"offset" : ((17 * 1024 * 1024)|tostring)}),
380 .digests."0".segments = ["0","2"] |
381 .digests."1".segments = ["1","3"] |
382 .config.requirements.mandatory = ["online-reencrypt"]'
383 img_check_fail_repair_ok
386 # NEW metadata (with reenc digest)
388 echo "[7] Reencryption with various mangled metadata"
395 # The same in various steps.
396 # Repair must validate not only metadata, but also reencryption digest.
398 img_update_json 'del(.digests."2")'
399 img_check_fail_repair_ok
401 img_prepare '--reduce-device-size 2M'
402 img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
405 #FIXME: cannot check with correct digest for now (--init-only does not store area type)
408 .keyslots."2".area.type = "checksum" |
409 .keyslots."2".area.hash = "sha256" |
410 .keyslots."2".area.sector_size = 4096'
414 img_update_json '.keyslots."2".area.type = "journal"'
418 img_update_json '.keyslots."2".mode = "decrypt"'
422 img_update_json '.keyslots."2".direction = "backward"'
427 img_update_json '.keyslots."2".key_size = 16'
432 img_update_json 'del(.segments."1")'
436 img_update_json '.segments."0".encryption = "aes-cbc-null"'
440 img_update_json '.segments."1".encryption = "aes-cbc-null"'
444 img_update_json '.segments."2".encryption = "aes-cbc-null"'
450 .digests."2" = .digests."0" |
451 .digests."2".keyslots = ["2"] |
452 .digests."2".segments = []'
456 img_update_json '.digests."2".iterations = 1111'
459 # Simulate correct progress
463 "0" : (.segments."0" +
464 {"size" : ((1 * 1024 * 1024)|tostring)}),
465 "1" : (.segments."0" +
466 {"offset" : ((17 * 1024 * 1024)|tostring)}),
470 .digests."0".segments = ["1","2"] |
471 .digests."1".segments = ["0","3"]'
476 # Set reencrypt slot to non-ignore priority
477 # This should be benign, just avoid noisy messages
479 img_update_json 'del(.keyslots."2".priority)'
484 # Remove mandatory reenc flag, but keep reenc metadata
486 img_update_json '.config.requirements.mandatory = []'
489 # Unknown segment flag, should be ignored
491 img_update_json '.segments."0".flags = ["dead-parrot"]'
494 echo "[8] Reencryption with AEAD is not supported"
498 .segments."0".integrity = {
499 "type" : "hmac(sha256)",
500 "journal_encryption": "none",
501 "journal_integrity": "none"
503 $CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail