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
12 IMG_HDR_BCP=$IMG_HDR.bcp
17 FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000"
18 CS_PWPARAMS="--disable-keyring --key-file $KEY1"
19 CS_PARAMS="-q --disable-locks $CS_PWPARAMS"
22 function remove_mapping()
24 [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
25 rm -f $IMG $IMG_HDR $IMG_HDR_BCP $IMG_JSON $KEY1 >/dev/null 2>&1
31 [ -n "$1" ] && echo "$1"
32 echo "FAILED backtrace:"
33 while caller $frame; do ((frame++)); done
40 [ -n "$1" ] && echo "$1"
47 command -v $1 >/dev/null || skip "WARNING: test require $1 binary, test skipped."
50 function img_json_save()
53 [ -z "$1" ] || _hdr="$1"
54 # FIXME: why --json-file cannot be used?
55 $CRYPTSETUP luksDump --dump-json-metadata $_hdr | jq -c -M . | tr -d '\n' >$IMG_JSON
58 function img_json_dump()
64 function img_hash_save()
66 IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1)
69 function img_hash_unchanged()
71 local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1)
72 [ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!"
75 function img_prepare_raw() # $1 options
79 if [ ! -e $KEY1 ]; then
80 dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
83 truncate -s 32M $IMG || fail
84 $CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail
87 function img_prepare() # $1 options
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()
105 local LUKS2_BIN1_OFFSET=448
106 local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE))
107 local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096))
109 # if present jq script, mangle JSON
111 local JSON=$(cat $IMG_JSON)
112 echo $JSON | jq -M -c "$1" >$IMG_JSON || fail
113 local JSON=$(cat $IMG_JSON)
114 echo $JSON | tr -d '\n' >$IMG_JSON || fail
117 [ -z "$2" ] || _hdr="$2"
120 _dd if=/dev/zero of=$_hdr count=$LUKS2_JSON_SIZE seek=4096
121 _dd if=/dev/zero of=$_hdr count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
124 _dd if=$IMG_JSON of=$_hdr count=$LUKS2_JSON_SIZE seek=4096
125 _dd if=$IMG_JSON of=$_hdr count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096))
127 # erase sha256 checksums
128 _dd if=/dev/zero of=$_hdr count=64 seek=$LUKS2_BIN1_OFFSET
129 _dd if=/dev/zero of=$_hdr count=64 seek=$LUKS2_BIN2_OFFSET
131 # calculate sha256 and write chexksums
132 local SUM1_HEX=$(_dd if=$_hdr count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
133 echo $SUM1_HEX | xxd -r -p | _dd of=$_hdr seek=$LUKS2_BIN1_OFFSET count=64 || fail
135 local SUM2_HEX=$(_dd if=$_hdr skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1)
136 echo $SUM2_HEX | xxd -r -p | _dd of=$_hdr seek=$LUKS2_BIN2_OFFSET count=64 || fail
141 function img_check_ok()
143 if [ $(id -u) == 0 ]; then
144 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail
145 $CRYPTSETUP close $DEV_NAME || fail
148 $CRYPTSETUP repair $IMG $CS_PARAMS || fail
151 function img_check_dump_ok()
153 $CRYPTSETUP luksDump $IMG >/dev/null || fail
157 function img_check_fail()
159 if [ $(id -u) == 0 ]; then
160 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
163 $CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail
167 function img_run_reenc_ok()
169 $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS -q --disable-locks --force-offline-reencrypt --resilience none || fail
172 function img_run_reenc_ok_data_shift()
174 $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS -q --disable-locks --force-offline-reencrypt || fail
177 function img_run_reenc_fail()
179 $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --force-offline-reencrypt --disable-locks -q 2>/dev/null && fail "Reencryption passed (should have failed)."
183 function img_check_fail_repair()
185 if [ $(id -u) == 0 ]; then
186 $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail
192 $CRYPTSETUP repair $IMG $CS_PARAMS || fail
197 function img_check_fail_repair_ok()
199 img_check_fail_repair
203 function img_check_fail_repair_ok_data_shift()
205 img_check_fail_repair
206 img_run_reenc_ok_data_shift
209 function valgrind_setup()
212 [ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable."
213 export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH"
214 CRYPTSETUP=valgrind_run
215 CRYPTSETUP_RAW="./valg.sh ${CRYPTSETUP_VALGRIND}"
218 function valgrind_run()
220 export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
224 [ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
232 [ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run
234 echo "[1] Reencryption with old flag is rejected"
236 img_update_json '.config.requirements.mandatory = ["online-reencryptx"]'
238 img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]'
243 # Simulate old reencryption with no digest (repairable)
245 img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]'
246 img_check_fail_repair_ok
248 # Simulate future version of reencrypt flag (should pass luksDump)
250 img_update_json '.config.requirements.mandatory = ["online-reencrypt-v999"]'
253 # Multiple reencrypt requirement flags makes LUKS2 invalid
255 img_update_json '.config.requirements.mandatory = .config.requirements.mandatory + ["online-reencrypt-v999"]'
259 img_update_json '.config.requirements.mandatory = .config.requirements.mandatory + ["online-reencrypt"]'
262 # just regular unknown requirement
264 img_update_json '.config.requirements.mandatory = .config.requirements.mandatory + ["online-reencrypt-v3X"]'
267 # This must fail for new releases
268 echo "[2] Old reencryption in-progress (journal)"
272 .keyslots."2".area.type = "journal" |
274 "0" : (.segments."0" +
275 {"size" : .keyslots."2".area.size} +
276 {"flags" : ["in-reencryption"]}),
277 "1" : (.segments."0" +
278 {"offset" : ((.segments."0".offset|tonumber) +
279 (.keyslots."2".area.size|tonumber))|tostring}),
283 .digests."0".segments = ["1","2"] |
284 .digests."1".segments = ["0","3"] |
285 .config.requirements.mandatory = ["online-reencrypt"]'
286 img_check_fail_repair_ok
288 echo "[3] Old reencryption in-progress (checksum)"
292 .keyslots."2".area.type = "checksum" |
293 .keyslots."2".area.hash = "sha256" |
294 .keyslots."2".area.sector_size = 4096 |
296 "0" : (.segments."0" +
297 {"size" : .keyslots."2".area.size} +
298 {"flags" : ["in-reencryption"]}),
299 "1" : (.segments."0" +
300 {"offset": ((.segments."0".offset|tonumber) +
301 (.keyslots."2".area.size|tonumber))|tostring}),
305 .digests."0".segments = ["1","2"] |
306 .digests."1".segments = ["0","3"] |
307 .config.requirements.mandatory = ["online-reencrypt"]'
308 img_check_fail_repair_ok
310 # Note: older tools cannot create this from commandline
311 echo "[4] Old decryption in-progress (journal)"
317 .keyslots."2".mode = "decrypt" |
318 .keyslots."2".area.type = "journal" |
322 "offset" : .segments."0".offset,
323 "size" : .keyslots."2".area.size,
324 "flags" : ["in-reencryption"]
326 "1" : (.segments."0" +
327 {"offset" : ((.segments."0".offset|tonumber) +
328 (.keyslots."2".area.size|tonumber))|tostring}),
332 "offset" : .segments."0".offset,
334 "flags" : ["backup-final"]
337 .digests."0".segments = ["1","2"] |
338 .config.requirements.mandatory = ["online-reencrypt"]'
339 img_check_fail_repair_ok
341 echo "[5] Old decryption in-progress (checksum)"
347 .keyslots."2".mode = "decrypt" |
348 .keyslots."2".area.type = "checksum" |
349 .keyslots."2".area.hash = "sha256" |
350 .keyslots."2".area.sector_size = 4096 |
354 "offset" : .segments."0".offset,
355 "size" : .keyslots."2".area.size,
356 "flags" : ["in-reencryption"]
358 "1" : (.segments."0" +
359 {"offset" : ((.segments."0".offset|tonumber) +
360 (.keyslots."2".area.size|tonumber))|tostring}),
364 "offset" : .segments."0".offset,
366 "flags" : ["backup-final"]
369 .digests."0".segments = ["1","2"] |
370 .config.requirements.mandatory = ["online-reencrypt"]'
371 img_check_fail_repair_ok
373 # Note - offset is set to work with the old version (with a datashift bug)
374 echo "[6] Old reencryption in-progress (datashift)"
378 .keyslots."2".direction = "backward" |
379 .keyslots."2".area.type = "datashift" |
380 .keyslots."2".area.size = "4096" |
381 .keyslots."2".area.shift_size = ((1 * 1024 * 1024)|tostring) |
383 "0" : (.segments."0" +
384 {"size" : ((13 * 1024 * 1024)|tostring)}),
385 "1" : (.segments."0" +
386 {"offset" : ((30 * 1024 * 1024)|tostring)}),
388 "3" : (.segments."2" +
389 {"offset" : ((17 * 1024 * 1024)|tostring)}),
391 .digests."0".segments = ["0","2"] |
392 .digests."1".segments = ["1","3"] |
393 .config.requirements.mandatory = ["online-reencrypt"]'
394 img_check_fail_repair_ok_data_shift
397 # NEW metadata (with reenc digest)
399 echo "[7] Reencryption with various mangled metadata"
406 # The same in various steps.
407 # Repair must validate not only metadata, but also reencryption digest.
409 img_update_json 'del(.digests."2")'
410 img_check_fail_repair_ok
412 img_prepare '--reduce-device-size 2M'
413 img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)'
418 .keyslots."2".area.type = "checksum" |
419 .keyslots."2".area.hash = "sha256" |
420 .keyslots."2".area.sector_size = 4096'
424 img_update_json '.keyslots."2".area.type = "journal"'
428 img_update_json '.keyslots."2".mode = "decrypt"'
432 img_update_json '.keyslots."2".direction = "backward"'
437 img_update_json '.keyslots."2".key_size = 16'
442 img_update_json 'del(.segments."1")'
446 img_update_json '.segments."0".encryption = "aes-cbc-null"'
450 img_update_json '.segments."1".encryption = "aes-cbc-null"'
454 img_update_json '.segments."2".encryption = "aes-cbc-null"'
460 .digests."2" = .digests."0" |
461 .digests."2".keyslots = ["2"] |
462 .digests."2".segments = []'
466 img_update_json '.digests."2".iterations = 1111'
469 # Simulate correct progress
473 "0" : (.segments."0" +
474 {"size" : ((1 * 1024 * 1024)|tostring)}),
475 "1" : (.segments."0" +
476 {"offset" : ((17 * 1024 * 1024)|tostring)}),
480 .digests."0".segments = ["1","2"] |
481 .digests."1".segments = ["0","3"]'
486 # Set reencrypt slot to non-ignore priority
487 # This should be benign, just avoid noisy messages
489 img_update_json 'del(.keyslots."2".priority)'
494 # Remove mandatory reenc flag, but keep reenc metadata
496 img_update_json '.config.requirements.mandatory = []'
499 # Unknown segment flag, should be ignored
501 img_update_json '.segments."0".flags = ["dead-parrot"]'
504 echo "[8] Reencryption with AEAD is not supported"
508 .segments."0".integrity = {
509 "type" : "hmac(sha256)",
510 "journal_encryption": "none",
511 "journal_integrity": "none"
513 $CRYPTSETUP reencrypt $IMG $CS_PARAMS >/dev/null 2>&1 && fail
515 echo "[9] Decryption with datashift"
517 $CRYPTSETUP reencrypt $CS_PARAMS --decrypt --init-only --force-offline-reencrypt --resilience checksum --header $IMG_HDR $IMG || fail
518 cp $IMG_HDR $IMG_HDR_BCP
521 img_json_save $IMG_HDR_BCP
522 img_update_json '.keyslots."1".area.hash = "sha12345"' $IMG_HDR
523 $CRYPTSETUP reencrypt --header $IMG_HDR $IMG $CS_PARAMS --force-offline-reencrypt 2>/dev/null && fail
526 img_json_save $IMG_HDR_BCP
527 img_update_json '.keyslots."1".area.sector_size = 1024' $IMG_HDR
528 $CRYPTSETUP reencrypt --header $IMG_HDR $IMG $CS_PARAMS --force-offline-reencrypt 2>/dev/null && fail
530 # replace with new resilience mode
531 img_json_save $IMG_HDR_BCP
532 img_update_json 'del(.keyslots."1".area.hash) |
533 del(.keyslots."1".sector_size) |
534 .keyslots."1".area.type = "datashift-journal"' $IMG_HDR
535 $CRYPTSETUP reencrypt --header $IMG_HDR $IMG $CS_PARAMS --force-offline-reencrypt 2>/dev/null && fail
537 # downgrade reencryption requirement
538 img_json_save $IMG_HDR_BCP
539 img_update_json '.config.requirements.mandatory = ["online-reencrypt-v2"]' $IMG_HDR
540 $CRYPTSETUP reencrypt --header $IMG_HDR $IMG $CS_PARAMS --force-offline-reencrypt 2>/dev/null && fail
542 # change datashift value
543 img_json_save $IMG_HDR_BCP
544 img_update_json '.keyslots."1".area.shift_size = (((.keyslots."1".area.shift_size | tonumber) - 4096) | tostring)' $IMG_HDR
545 $CRYPTSETUP reencrypt --header $IMG_HDR $IMG $CS_PARAMS --force-offline-reencrypt 2>/dev/null && fail