diff --git a/tests/Makefile.am b/tests/Makefile.am index 2efb12b4..8e7ad4c1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,7 @@ TESTS = api-test \ + api-test-2 \ compat-test \ + compat-test2 \ loopaes-test \ align-test \ discards-test \ @@ -8,7 +10,9 @@ TESTS = api-test \ tcrypt-compat-test \ luks1-compat-test \ device-test \ - keyring-test + keyring-test \ + luks2-validation-test \ + luks2-integrity-test if VERITYSETUP TESTS += verity-compat-test @@ -23,8 +27,15 @@ TESTS += integrity-compat-test endif EXTRA_DIST = compatimage.img.bz2 compatv10image.img.bz2 \ + compatimage2.img.xz \ + conversion_imgs.tar.xz \ + luks2_keyslot_unassigned.img.xz \ img_fs_ext4.img.bz2 img_fs_vfat.img.bz2 img_fs_xfs.img.bz2 \ valid_header_file.bz2 \ + luks2_header_file.xz \ + luks2_valid_hdr.img.xz \ + luks2_header_requirements.xz \ + luks2_header_requirements_free.xz \ evil_hdr-payload_overwrite.bz2 \ evil_hdr-stripes_payload_dmg.bz2 \ evil_hdr-luks_hdr_damage.bz2 \ @@ -32,11 +43,15 @@ EXTRA_DIST = compatimage.img.bz2 compatv10image.img.bz2 \ evil_hdr-keyslot_overlap.bz2 \ tcrypt-images.tar.bz2 \ luks1-images.tar.bz2 \ - compat-test loopaes-test align-test discards-test mode-test password-hash-test \ + compat-test \ + compat-test2 \ + loopaes-test align-test discards-test mode-test password-hash-test \ verity-compat-test \ reencryption-compat-test \ tcrypt-compat-test \ luks1-compat-test \ + luks2-validation-test generators \ + luks2-integrity-test \ device-test \ keyring-test \ integrity-compat-test \ @@ -44,7 +59,7 @@ EXTRA_DIST = compatimage.img.bz2 compatv10image.img.bz2 \ CLEANFILES = cryptsetup-tst* valglog* clean-local: - -rm -rf tcrypt-images luks1-images + -rm -rf tcrypt-images luks1-images luks2-images conversion_imgs luks2_valid_hdr.img differ_SOURCES = differ.c differ_CFLAGS = $(AM_CFLAGS) -Wall -O2 @@ -55,13 +70,25 @@ api_test_LDFLAGS = $(AM_LDFLAGS) -static api_test_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib/ -I$(top_srcdir)/lib/luks1 api_test_CPPFLAGS = $(AM_CPPFLAGS) -include config.h -check_PROGRAMS = api-test differ +api_test_2_SOURCES = api-test-2.c api_test.h test_utils.c $(top_srcdir)/lib/utils_loop.c +api_test_2_LDADD = ../lib/libcryptsetup.la +api_test_2_LDFLAGS = $(AM_LDFLAGS) -static +api_test_2_CFLAGS = -g -Wall -O0 $(AM_CFLAGS) -I$(top_srcdir)/lib/ -I$(top_srcdir)/lib/luks1 +api_test_2_CPPFLAGS = $(AM_CPPFLAGS) -include config.h + +check_PROGRAMS = api-test api-test-2 differ + +conversion_imgs: + @tar xJf conversion_imgs.tar.xz compatimage.img: @bzip2 -k -d compatimage.img.bz2 -valgrind-check: api-test differ +valgrind-check: api-test api-test-2 differ @VALG=1 ./compat-test + @VALG=1 ./compat-test2 + @VALG=1 ./luks2-validation-test @INFOSTRING="api-test-000" ./valg-api.sh ./api-test + @INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2 .PHONY: valgrind-check diff --git a/tests/api-test-2.c b/tests/api-test-2.c new file mode 100644 index 00000000..05b37d40 --- /dev/null +++ b/tests/api-test-2.c @@ -0,0 +1,2744 @@ +/* + * cryptsetup library LUKS2 API check functions + * + * Copyright (C) 2009-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2009-2017, Milan Broz + * Copyright (C) 2016-2017, Ondrej Kozina + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef KERNEL_KEYRING +#include +#include +#ifndef HAVE_KEY_SERIAL_T +#define HAVE_KEY_SERIAL_T +#include +typedef int32_t key_serial_t; +#endif +#endif + +#include "api_test.h" +#include "luks.h" +#include "libcryptsetup.h" +#include "utils_loop.h" + +#define DMDIR "/dev/mapper/" + +#define DEVICE_1_UUID "28632274-8c8a-493f-835b-da802e1c576b" +#define DEVICE_EMPTY_name "crypt_zero" +#define DEVICE_EMPTY DMDIR DEVICE_EMPTY_name +#define DEVICE_ERROR_name "crypt_error" +#define DEVICE_ERROR DMDIR DEVICE_ERROR_name + +#define CDEVICE_1 "ctest1" +#define CDEVICE_2 "ctest2" +#define CDEVICE_WRONG "O_o" +#define H_DEVICE "head_ok" +#define H_DEVICE_WRONG "head_wr" +#define L_DEVICE_1S "luks_onesec" +#define L_DEVICE_0S "luks_zerosec" +#define L_DEVICE_WRONG "luks_wr" +#define L_DEVICE_OK "luks_ok" +#define VALID_LUKS2_HEADER "luks2_header_file" +#define REQS_LUKS2_HEADER "luks2_header_requirements" +#define NO_REQS_LUKS2_HEADER "luks2_header_requirements_free" +#define BACKUP_FILE "csetup_backup_file" +#define IMAGE1 "compatimage2.img" +#define IMAGE_EMPTY "empty.img" + +#define KEYFILE1 "key1.file" +#define KEY1 "compatkey" + +#define KEYFILE2 "key2.file" +#define KEY2 "0123456789abcdef" + +#define PASSPHRASE "blabla" +#define PASSPHRASE1 "albalb" + +#define DEVICE_TEST_UUID "12345678-1234-1234-1234-123456789abc" + +#define DEVICE_WRONG "/dev/Ooo_" +#define DEVICE_CHAR "/dev/zero" +#define THE_LFILE_TEMPLATE "cryptsetup-tstlp.XXXXXX" + +#define KEY_DESC_TEST0 "cs_token_test:test_key0" +#define KEY_DESC_TEST1 "cs_token_test:test_key1" + +#define CONV_DIR "conversion_imgs" +#define CONV_L1_128 "l1_128b" +#define CONV_L1_256 "l1_256b" +#define CONV_L1_512 "l1_512b" +#define CONV_L2_128 "l2_128b" +#define CONV_L2_128_FULL "l2_128b_full" +#define CONV_L2_256 "l2_256b" +#define CONV_L2_256_FULL "l2_256b_full" +#define CONV_L2_512 "l2_512b" +#define CONV_L2_512_FULL "l2_512b_full" +#define CONV_L1_128_DET "l1_128b_det" +#define CONV_L1_256_DET "l1_256b_det" +#define CONV_L1_512_DET "l1_512b_det" +#define CONV_L2_128_DET "l2_128b_det" +#define CONV_L2_128_DET_FULL "l2_128b_det_full" +#define CONV_L2_256_DET "l2_256b_det" +#define CONV_L2_256_DET_FULL "l2_256b_det_full" +#define CONV_L2_512_DET "l2_512b_det" +#define CONV_L2_512_DET_FULL "l2_512b_det_full" +#define CONV_L1_256_LEGACY "l1_256b_legacy_offset" +#define CONV_L1_256_UNMOVABLE "l1_256b_unmovable" +#define PASS0 "aaa" +#define PASS1 "hhh" +#define PASS2 "ccc" +#define PASS3 "ddd" +#define PASS4 "eee" +#define PASS5 "fff" +#define PASS6 "ggg" +#define PASS7 "bbb" +#define PASS8 "iii" + +static int _fips_mode = 0; + +static char *DEVICE_1 = NULL; +static char *DEVICE_2 = NULL; +static char *DEVICE_3 = NULL; +static char *DEVICE_4 = NULL; +static char *DEVICE_5 = NULL; +static char *DEVICE_6 = NULL; + +static char *tmp_file_1 = NULL; +static char *test_loop_file = NULL; + +// Helpers + +static unsigned cpus_online(void) +{ + static long r = -1; + + if (r < 0) { + r = sysconf(_SC_NPROCESSORS_ONLN); + if (r < 0) + r = 1; + } + + return r; +} + +static unsigned _min(unsigned a, unsigned b) +{ + return a < b ? a : b; +} + +/* FIXME: will fail with various LUKS2 header sizes */ +static int get_luks2_offsets(int metadata_device, + unsigned int alignpayload_sec, + unsigned int alignoffset_sec, /* unused in LUKS2, bug? */ + unsigned int sector_size, + uint64_t *r_header_size, + uint64_t *r_payload_offset) +{ + if (!sector_size) + sector_size = 512; /* default? */ + + if ((sector_size % 512) && (sector_size % 4096)) + return -1; + + if (r_payload_offset) { + if (metadata_device) + *r_payload_offset = DIV_ROUND_UP_MODULO(4*1024*1024, (alignpayload_sec ?: 1) * sector_size); + else + *r_payload_offset = alignpayload_sec * sector_size; + + *r_payload_offset /= sector_size; + } + + if (r_header_size) + *r_header_size = (4*1024*1024) / sector_size; + + return 0; +} + +static void _remove_keyfiles(void) +{ + remove(KEYFILE1); + remove(KEYFILE2); +} + +#if HAVE_DECL_DM_TASK_RETRY_REMOVE +#define DM_RETRY "--retry " +#else +#define DM_RETRY "" +#endif + +static void _cleanup_dmdevices(void) +{ + struct stat st; + + if (!stat(DMDIR H_DEVICE, &st)) + _system("dmsetup remove " DM_RETRY H_DEVICE, 0); + + if (!stat(DMDIR H_DEVICE_WRONG, &st)) + _system("dmsetup remove " DM_RETRY H_DEVICE_WRONG, 0); + + if (!stat(DMDIR L_DEVICE_0S, &st)) + _system("dmsetup remove " DM_RETRY L_DEVICE_0S, 0); + + if (!stat(DMDIR L_DEVICE_1S, &st)) + _system("dmsetup remove " DM_RETRY L_DEVICE_1S, 0); + + if (!stat(DMDIR L_DEVICE_WRONG, &st)) + _system("dmsetup remove " DM_RETRY L_DEVICE_WRONG, 0); + + if (!stat(DMDIR L_DEVICE_OK, &st)) + _system("dmsetup remove " DM_RETRY L_DEVICE_OK, 0); + + t_dev_offset = 0; +} + +static void _cleanup(void) +{ + struct stat st; + + //_system("udevadm settle", 0); + + if (!stat(DMDIR CDEVICE_1, &st)) + _system("dmsetup remove " CDEVICE_1, 0); + + if (!stat(DMDIR CDEVICE_2, &st)) + _system("dmsetup remove " CDEVICE_2, 0); + + if (!stat(DEVICE_EMPTY, &st)) + _system("dmsetup remove " DEVICE_EMPTY_name, 0); + + if (!stat(DEVICE_ERROR, &st)) + _system("dmsetup remove " DEVICE_ERROR_name, 0); + + _cleanup_dmdevices(); + + if (crypt_loop_device(THE_LOOP_DEV)) + crypt_loop_detach(THE_LOOP_DEV); + + if (crypt_loop_device(DEVICE_1)) + crypt_loop_detach(DEVICE_1); + + if (crypt_loop_device(DEVICE_2)) + crypt_loop_detach(DEVICE_2); + + if (crypt_loop_device(DEVICE_3)) + crypt_loop_detach(DEVICE_3); + + if (crypt_loop_device(DEVICE_4)) + crypt_loop_detach(DEVICE_4); + + if (crypt_loop_device(DEVICE_5)) + crypt_loop_detach(DEVICE_5); + + if (crypt_loop_device(DEVICE_6)) + crypt_loop_detach(DEVICE_6); + + _system("rm -f " IMAGE_EMPTY, 0); + _system("rm -f " IMAGE1, 0); + _system("rm -rf " CONV_DIR, 0); + + remove(test_loop_file); + remove(tmp_file_1); + + remove(VALID_LUKS2_HEADER); + remove(REQS_LUKS2_HEADER); + remove(NO_REQS_LUKS2_HEADER); + remove(BACKUP_FILE); + + _remove_keyfiles(); + + free(tmp_file_1); + free(test_loop_file); + free(THE_LOOP_DEV); + free(DEVICE_1); + free(DEVICE_2); + free(DEVICE_3); + free(DEVICE_4); + free(DEVICE_5); + free(DEVICE_6); +} + +static int _setup(void) +{ + int fd, ro = 0; + char cmd[128]; + + test_loop_file = strdup(THE_LFILE_TEMPLATE); + if ((fd=mkstemp(test_loop_file)) == -1) { + printf("cannot create temporary file with template %s\n", test_loop_file); + return 1; + } + close(fd); + snprintf(cmd, sizeof(cmd), "dd if=/dev/zero of=%s bs=%d count=%d 2>/dev/null", + test_loop_file, SECTOR_SIZE, TST_LOOP_FILE_SIZE); + if (_system(cmd, 1)) + return 1; + + fd = crypt_loop_attach(&THE_LOOP_DEV, test_loop_file, 0, 0, &ro); + close(fd); + + tmp_file_1 = strdup(THE_LFILE_TEMPLATE); + if ((fd=mkstemp(tmp_file_1)) == -1) { + printf("cannot create temporary file with template %s\n", tmp_file_1); + return 1; + } + close(fd); + snprintf(cmd, sizeof(cmd), "dd if=/dev/zero of=%s bs=%d count=%d 2>/dev/null", + tmp_file_1, SECTOR_SIZE, 10); + if (_system(cmd, 1)) + return 1; + + _system("dmsetup create " DEVICE_EMPTY_name " --table \"0 10000 zero\"", 1); + _system("dmsetup create " DEVICE_ERROR_name " --table \"0 10000 error\"", 1); + + _system(" [ ! -e " IMAGE1 " ] && xz -dk " IMAGE1 ".xz", 1); + fd = crypt_loop_attach(&DEVICE_1, IMAGE1, 0, 0, &ro); + close(fd); + + _system("dd if=/dev/zero of=" IMAGE_EMPTY " bs=1M count=32 2>/dev/null", 1); + fd = crypt_loop_attach(&DEVICE_2, IMAGE_EMPTY, 0, 0, &ro); + close(fd); + + _system(" [ ! -e " VALID_LUKS2_HEADER " ] && xz -dk " VALID_LUKS2_HEADER ".xz", 1); + fd = crypt_loop_attach(&DEVICE_4, VALID_LUKS2_HEADER, 0, 0, &ro); + close(fd); + + _system(" [ ! -e " REQS_LUKS2_HEADER " ] && xz -dk " REQS_LUKS2_HEADER ".xz", 1); + fd = crypt_loop_attach(&DEVICE_5, REQS_LUKS2_HEADER, 0, 0, &ro); + close(fd); + + _system(" [ ! -e " NO_REQS_LUKS2_HEADER " ] && xz -dk " NO_REQS_LUKS2_HEADER ".xz", 1); + fd = crypt_loop_attach(&DEVICE_6, NO_REQS_LUKS2_HEADER, 0, 0, &ro); + close(fd); + + _system(" [ ! -d " CONV_DIR " ] && tar xJf " CONV_DIR ".tar.xz", 1); + + if (_system("modprobe dm-crypt", 1)) + return 1; + + if (t_dm_check_versions()) + return 1; + + _system("rmmod dm-crypt", 0); + + _fips_mode = fips_mode(); + if (_debug) + printf("FIPS MODE: %d\n", _fips_mode); + + /* Use default log callback */ + crypt_set_log_callback(NULL, &global_log_callback, NULL); + + return 0; +} + +#ifdef KERNEL_KEYRING +static key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t keyring) +{ + return syscall(__NR_add_key, type, description, payload, plen, keyring); +} + +static key_serial_t keyctl_unlink(key_serial_t key, key_serial_t keyring) +{ + return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring); +} + +static key_serial_t request_key(const char *type, + const char *description, + const char *callout_info, + key_serial_t keyring) +{ + return syscall(__NR_request_key, type, description, callout_info, keyring); +} + +static key_serial_t _kernel_key_by_segment(struct crypt_device *cd, int segment) +{ + char key_description[1024]; + + if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-%u", crypt_get_uuid(cd), segment) < 1) + return -1; + + return request_key("logon", key_description, NULL, 0); +} + +static int _volume_key_in_keyring(struct crypt_device *cd, int segment) +{ + return _kernel_key_by_segment(cd, segment); +} + +static int _drop_keyring_key(struct crypt_device *cd, int segment) +{ + key_serial_t kid = _kernel_key_by_segment(cd, segment); + + if (kid < 0) + return -1; + + return keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING); +} +#endif + +static int test_open(struct crypt_device *cd, + int token, + char **buffer, + size_t *buffer_len, + void *usrptr) +{ + const char *str = (const char *)usrptr; + char *buf = malloc(strlen(str)); + if (!buf) + return -ENOMEM; + + strncpy(buf, str, strlen(str)); + *buffer = buf; + *buffer_len = strlen(str); + + return 0; +} + +static int test_validate(struct crypt_device *cd, const char *json) +{ + return (strstr(json, "magic_string") == NULL); +} + +static void UseLuks2Device(void) +{ + struct crypt_device *cd; + char key[128]; + size_t key_size; + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0), "already open"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + FAIL_(crypt_deactivate(cd, CDEVICE_1), "no such device"); + +#if KERNEL_KEYRING + // repeat previous tests and check kernel keyring is released when not needed + if (t_dm_crypt_keyring_support()) { + OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + FAIL_(_drop_keyring_key(cd, 0), ""); + OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), CRYPT_ACTIVATE_KEYRING_KEY)); + OK_(_drop_keyring_key(cd, 0)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + OK_(_drop_keyring_key(cd, 0)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0), "already open"); + FAIL_(_volume_key_in_keyring(cd, 0), ""); + OK_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + FAIL_(_volume_key_in_keyring(cd, 0), ""); + } +#endif + + key_size = 16; + OK_(strcmp("aes", crypt_get_cipher(cd))); + OK_(strcmp("cbc-essiv:sha256", crypt_get_cipher_mode(cd))); + OK_(strcmp(DEVICE_1_UUID, crypt_get_uuid(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); + EQ_(8192, crypt_get_data_offset(cd)); + + if (!_fips_mode) { + EQ_(0, crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, KEY1, strlen(KEY1))); + OK_(crypt_volume_key_verify(cd, key, key_size)); + OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + + key[1] = ~key[1]; + FAIL_(crypt_volume_key_verify(cd, key, key_size), "key mismatch"); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "key mismatch"); + } + crypt_free(cd); +} + +static void SuspendDevice(void) +{ + int suspend_status; + struct crypt_device *cd; + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + + suspend_status = crypt_suspend(cd, CDEVICE_1); + if (suspend_status == -ENOTSUP) { + printf("WARNING: Suspend/Resume not supported, skipping test.\n"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + return; + } + + OK_(suspend_status); + FAIL_(crypt_suspend(cd, CDEVICE_1), "already suspended"); + + FAIL_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)-1), "wrong key"); + OK_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1))); + FAIL_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)), "not suspended"); + + OK_(prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); + OK_(crypt_suspend(cd, CDEVICE_1)); + FAIL_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1 "blah", 0), "wrong keyfile"); + FAIL_(crypt_resume_by_keyfile_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 1, 0), "wrong key"); + OK_(crypt_resume_by_keyfile_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0)); + FAIL_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0), "not suspended"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + /* create LUKS device with detached header */ + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DEVICE_2)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1), 0)); + crypt_free(cd); + + /* Should be able to suspend but not resume if not header specified */ + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(crypt_suspend(cd, CDEVICE_1)); + FAIL_(crypt_suspend(cd, CDEVICE_1), "already suspended"); + FAIL_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)-1), "no header"); + crypt_free(cd); + + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DEVICE_1)); + OK_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1))); + + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + _remove_keyfiles(); +} + +static void AddDeviceLuks2(void) +{ + struct crypt_device *cd; + struct crypt_pbkdf_type pbkdf = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha256", + .parallel_threads = 4, + .max_memory_kb = 1024, + .time_ms = 1 + }; + struct crypt_params_luks2 params = { + .pbkdf = &pbkdf, + .data_device = DEVICE_2, + .sector_size = 512 + }; + char key[128], key2[128], key3[128]; + + const char *passphrase = "blabla", *passphrase2 = "nsdkFI&Y#.sd"; + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e"; + size_t key_size = strlen(mk_hex) / 2; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + uint64_t r_payload_offset, r_header_size, r_size_1; + + crypt_decode_key(key, mk_hex, key_size); + crypt_decode_key(key3, mk_hex2, key_size); + + // init test devices + OK_(get_luks2_offsets(1, 0, 0, 0, &r_header_size, &r_payload_offset)); + OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size)); + OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_header_size - 1)); + + // format + OK_(crypt_init(&cd, DMDIR H_DEVICE_WRONG)); + params.data_alignment = 0; + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Not enough space for keyslots material"); + crypt_free(cd); + + // test payload_offset = 0 for encrypted device with external header device + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + EQ_(crypt_get_data_offset(cd), 0); + crypt_free(cd); + + params.data_alignment = 0; + params.data_device = NULL; + + // test payload_offset = 0. format() should look up alignment offset from device topology + OK_(crypt_init(&cd, DEVICE_2)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(!(crypt_get_data_offset(cd) > 0)); + crypt_free(cd); + + /* + * test limit values for backing device size + */ + params.data_alignment = 8192; + OK_(get_luks2_offsets(0, params.data_alignment, 0, 0, NULL, &r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_0S, r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1)); + OK_(create_dmdevice_over_loop(L_DEVICE_WRONG, r_payload_offset - 1)); + + // 1 sector less than required + OK_(crypt_init(&cd, DMDIR L_DEVICE_WRONG)); + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Device too small"); + crypt_free(cd); + + // 0 sectors for encrypted area + OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Encrypted area too small"); + crypt_free(cd); + + // 1 sector for encrypted area + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + EQ_(crypt_get_data_offset(cd), params.data_alignment); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(t_device_size(DMDIR CDEVICE_1, &r_size_1)); + EQ_(r_size_1, SECTOR_SIZE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + // restrict format only to empty context + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Context is already formated"); + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL), "Context is already formated"); + // change data device to wrong one + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_0S)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device too small"); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_1S)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + params.data_alignment = 0; + params.data_device = DEVICE_2; + + // generate keyslot material at the end of luks header + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase)), 7); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase) ,0), 7); + crypt_free(cd); + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE)); + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Context is already formated"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + crypt_free(cd); + // check active status without header + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, NULL)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + NULL_(crypt_get_type(cd)); + OK_(strcmp(cipher, crypt_get_cipher(cd))); + OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + params.data_alignment = 2048; + params.data_device = NULL; + + // test uuid mismatch and _init_by_name_and_header + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + crypt_free(cd); + params.data_alignment = 0; + params.data_device = DEVICE_2; + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + crypt_free(cd); + // there we've got uuid mismatch + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + NULL_(crypt_get_type(cd)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device is active"); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0), "Device is active"); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_INACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + params.data_device = NULL; + + OK_(crypt_init(&cd, DEVICE_2)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + + // even with no keyslots defined it can be activated by volume key + OK_(crypt_volume_key_verify(cd, key, key_size)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, key, key_size, 0)); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_2)); + + // now with keyslot + EQ_(7, crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase))); + EQ_(CRYPT_SLOT_ACTIVE_LAST, crypt_keyslot_status(cd, 7)); + EQ_(7, crypt_activate_by_passphrase(cd, CDEVICE_2, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0)); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_2)); + + crypt_set_iteration_time(cd, 1); + EQ_(1, crypt_keyslot_add_by_volume_key(cd, 1, key, key_size, KEY1, strlen(KEY1))); + OK_(prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); + OK_(prepare_keyfile(KEYFILE2, KEY2, strlen(KEY2))); + EQ_(2, crypt_keyslot_add_by_keyfile(cd, 2, KEYFILE1, 0, KEYFILE2, 0)); + FAIL_(crypt_keyslot_add_by_keyfile_offset(cd, 3, KEYFILE1, 0, 1, KEYFILE2, 0, 1), "wrong key"); + EQ_(3, crypt_keyslot_add_by_keyfile_offset(cd, 3, KEYFILE1, 0, 0, KEYFILE2, 0, 1)); + EQ_(4, crypt_keyslot_add_by_keyfile_offset(cd, 4, KEYFILE2, 0, 1, KEYFILE1, 0, 1)); + FAIL_(crypt_activate_by_keyfile(cd, CDEVICE_2, CRYPT_ANY_SLOT, KEYFILE2, strlen(KEY2)-1, 0), "key mismatch"); + EQ_(2, crypt_activate_by_keyfile(cd, NULL, CRYPT_ANY_SLOT, KEYFILE2, 0, 0)); + EQ_(3, crypt_activate_by_keyfile_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE2, 0, 1, 0)); + EQ_(4, crypt_activate_by_keyfile_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, 1, 0)); + FAIL_(crypt_activate_by_keyfile_offset(cd, CDEVICE_2, CRYPT_ANY_SLOT, KEYFILE2, strlen(KEY2), 2, 0), "not enough data"); + FAIL_(crypt_activate_by_keyfile_offset(cd, CDEVICE_2, CRYPT_ANY_SLOT, KEYFILE2, 0, strlen(KEY2) + 1, 0), "cannot seek"); + FAIL_(crypt_activate_by_keyfile_offset(cd, CDEVICE_2, CRYPT_ANY_SLOT, KEYFILE2, 0, 2, 0), "wrong key"); + EQ_(2, crypt_activate_by_keyfile(cd, CDEVICE_2, CRYPT_ANY_SLOT, KEYFILE2, 0, 0)); + OK_(crypt_keyslot_destroy(cd, 1)); + OK_(crypt_keyslot_destroy(cd, 2)); + OK_(crypt_keyslot_destroy(cd, 3)); + OK_(crypt_keyslot_destroy(cd, 4)); + OK_(crypt_deactivate(cd, CDEVICE_2)); + _remove_keyfiles(); + + FAIL_(crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase)), "slot used"); + key[1] = ~key[1]; + FAIL_(crypt_keyslot_add_by_volume_key(cd, 6, key, key_size, passphrase, strlen(passphrase)), "key mismatch"); + key[1] = ~key[1]; + EQ_(6, crypt_keyslot_add_by_volume_key(cd, 6, key, key_size, passphrase, strlen(passphrase))); + EQ_(CRYPT_SLOT_ACTIVE, crypt_keyslot_status(cd, 6)); + + FAIL_(crypt_keyslot_destroy(cd, 8), "invalid keyslot"); + FAIL_(crypt_keyslot_destroy(cd, CRYPT_ANY_SLOT), "invalid keyslot"); + FAIL_(crypt_keyslot_destroy(cd, 0), "keyslot not used"); + OK_(crypt_keyslot_destroy(cd, 7)); + EQ_(CRYPT_SLOT_INACTIVE, crypt_keyslot_status(cd, 7)); + EQ_(CRYPT_SLOT_ACTIVE_LAST, crypt_keyslot_status(cd, 6)); + + EQ_(7, crypt_keyslot_change_by_passphrase(cd, 6, 7, passphrase, strlen(passphrase), passphrase2, strlen(passphrase2))); + EQ_(CRYPT_SLOT_ACTIVE_LAST, crypt_keyslot_status(cd, 7)); + EQ_(7, crypt_activate_by_passphrase(cd, NULL, 7, passphrase2, strlen(passphrase2), 0)); + EQ_(6, crypt_keyslot_change_by_passphrase(cd, CRYPT_ANY_SLOT, 6, passphrase2, strlen(passphrase2), passphrase, strlen(passphrase))); + + if (!_fips_mode) { + EQ_(6, crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key2, &key_size, passphrase, strlen(passphrase))); + OK_(crypt_volume_key_verify(cd, key2, key_size)); + + OK_(memcmp(key, key2, key_size)); + } + OK_(strcmp(cipher, crypt_get_cipher(cd))); + OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); + EQ_(8192, crypt_get_data_offset(cd)); + OK_(strcmp(DEVICE_2, crypt_get_device_name(cd))); + + reset_log(); + OK_(crypt_dump(cd)); + OK_(!(global_lines != 0)); + reset_log(); + + FAIL_(crypt_set_uuid(cd, "blah"), "wrong UUID format"); + OK_(crypt_set_uuid(cd, DEVICE_TEST_UUID)); + OK_(strcmp(DEVICE_TEST_UUID, crypt_get_uuid(cd))); + + FAIL_(crypt_deactivate(cd, CDEVICE_2), "not active"); + crypt_free(cd); + _cleanup_dmdevices(); + + /* LUKSv2 format tests */ + + /* very basic test */ + OK_(crypt_init(&cd, DEVICE_2)); + crypt_set_iteration_time(cd, 1); + FAIL_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 0, NULL), "Wrong key size"); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); + crypt_free(cd); + /* some invalid parameters known to cause troubles */ + OK_(crypt_init(&cd, DEVICE_2)); + crypt_set_iteration_time(cd, 0); /* wrong for argon2 but we don't know the pbkdf type yet, ignored */ + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); + crypt_free(cd); + OK_(crypt_init(&cd, DEVICE_2)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, key_size, PASSPHRASE, strlen(PASSPHRASE)), 0); + crypt_free(cd); + + OK_(crypt_init(&cd, DEVICE_2)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, key_size, NULL)); + FAIL_(crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, key, key_size, PASSPHRASE, strlen(PASSPHRASE)), "VK doesn't match any digest"); + FAIL_(crypt_keyslot_add_by_volume_key(cd, 1, key, key_size, PASSPHRASE, strlen(PASSPHRASE)), "VK doesn't match any digest"); + crypt_free(cd); + + OK_(create_dmdevice_over_loop(L_DEVICE_1S, 8193)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 3, NULL, key_size, PASSPHRASE, strlen(PASSPHRASE)), 3); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key3, key_size, 0), "VK doesn't match any digest assigned to segment 0"); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void UseTempVolumes(void) +{ + struct crypt_device *cd; + char tmp[256]; + + // Tepmporary device without keyslot but with on-disk LUKS header + OK_(crypt_init(&cd, DEVICE_2)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "not yet formatted"); + OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 16, NULL)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0)); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE); + crypt_free(cd); + + OK_(crypt_init_by_name(&cd, CDEVICE_2)); + OK_(crypt_deactivate(cd, CDEVICE_2)); + crypt_free(cd); + + // Dirty checks: device without UUID + // we should be able to remove it but not manuipulate with it + snprintf(tmp, sizeof(tmp), "dmsetup create %s --table \"" + "0 100 crypt aes-cbc-essiv:sha256 deadbabedeadbabedeadbabedeadbabe 0 " + "%s 2048\"", CDEVICE_2, DEVICE_2); + _system(tmp, 1); + OK_(crypt_init_by_name(&cd, CDEVICE_2)); + OK_(crypt_deactivate(cd, CDEVICE_2)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "No known device type"); + crypt_free(cd); + + // Dirty checks: device with UUID but LUKS header key fingerprint must fail) + snprintf(tmp, sizeof(tmp), "dmsetup create %s --table \"" + "0 100 crypt aes-cbc-essiv:sha256 deadbabedeadbabedeadbabedeadbabe 0 " + "%s 2048\" -u CRYPT-LUKS2-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-ctest1", + CDEVICE_2, DEVICE_2); + _system(tmp, 1); + OK_(crypt_init_by_name(&cd, CDEVICE_2)); + OK_(crypt_deactivate(cd, CDEVICE_2)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "wrong volume key"); + crypt_free(cd); + + // No slots + OK_(crypt_init(&cd, DEVICE_2)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "volume key is lost"); + crypt_free(cd); +} + +static void Luks2HeaderRestore(void) +{ + struct crypt_device *cd; + struct crypt_pbkdf_type pbkdf = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha256", + .parallel_threads = 4, + .max_memory_kb = 1024, + .time_ms = 1 + }; + struct crypt_params_luks2 params = { + .pbkdf = &pbkdf, + .data_alignment = 8192, // 4M, data offset will be 4096 + .sector_size = 512 + }; + struct crypt_params_plain pl_params = { + .hash = "sha1", + .skip = 0, + .offset = 0, + .size = 0 + }; + struct crypt_params_luks1 luks1 = { + .data_alignment = 8192, // 4M offset to pass alignement test + }; + char key[128]; + + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + size_t key_size = strlen(mk_hex) / 2; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + uint64_t r_payload_offset; + + crypt_decode_key(key, mk_hex, key_size); + + OK_(get_luks2_offsets(0, params.data_alignment, 0, 0, NULL, &r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 5000)); + + // do not restore header over plain device + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, &pl_params)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + FAIL_(crypt_header_restore(cd, CRYPT_PLAIN, VALID_LUKS2_HEADER), "Cannot restore header to PLAIN type device"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, VALID_LUKS2_HEADER), "Cannot restore header over PLAIN type device"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // FIXME: does following test make a sense in LUKS2? + // volume key_size mismatch + // OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + // memcpy(key2, key, key_size / 2); + // OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key2, key_size / 2, ¶ms)); + // FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, VALID_LUKS2_HEADER), "Volume keysize mismatch"); + // crypt_free(cd); + + // payload offset mismatch + params.data_alignment = 8193; + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, VALID_LUKS2_HEADER), "Payload offset mismatch"); + crypt_free(cd); + params.data_alignment = 4096; + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + // FIXME: either format has to fail or next line must be true + // EQ_(crypt_get_data_offset(cd), params.data_alignment); + // FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, VALID_LUKS2_HEADER), "Payload offset mismatch"); + crypt_free(cd); + + // do not allow restore over LUKS1 header on device + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, NULL, 32, &luks1)); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS2, VALID_LUKS2_HEADER), "LUKS1 format detected"); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void Luks2HeaderLoad(void) +{ + struct crypt_device *cd; + struct crypt_pbkdf_type pbkdf = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha256", + .parallel_threads = 4, + .max_memory_kb = 1024, + .time_ms = 1 + }; + struct crypt_params_luks2 params = { + .pbkdf = &pbkdf, + .data_alignment = 8192, // 4M, data offset will be 4096 + .data_device = DEVICE_2, + .sector_size = 512 + }; + struct crypt_params_plain pl_params = { + .hash = "sha1", + .skip = 0, + .offset = 0, + .size = 0 + }; + char key[128], cmd[256]; + + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + size_t key_size = strlen(mk_hex) / 2; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + uint64_t r_payload_offset, r_header_size; + + crypt_decode_key(key, mk_hex, key_size); + + // prepare test env + OK_(get_luks2_offsets(0, params.data_alignment, 0, 0, &r_header_size, &r_payload_offset)); + // external header device + OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size)); + // prepared header on a device too small to contain header and payload + //OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_payload_offset - 1)); + OK_(create_dmdevice_over_loop(H_DEVICE_WRONG, r_header_size - 1)); + snprintf(cmd, sizeof(cmd), "dd if=" IMAGE1 " of=" DMDIR H_DEVICE_WRONG " bs=%" PRIu32 " count=%" PRIu64 " 2>/dev/null", params.sector_size, r_header_size - 1); + OK_(_system(cmd, 1)); + // some device + OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1000)); + // 1 sector device + OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_header_size + 1)); + // 0 sectors device for payload + OK_(create_dmdevice_over_loop(L_DEVICE_0S, r_header_size)); + + // valid metadata and device size + params.data_alignment = 0; + params.data_device = DMDIR L_DEVICE_OK; + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // bad header: device too small (payloadOffset > device_size) + OK_(crypt_init(&cd, DMDIR H_DEVICE_WRONG)); + FAIL_(crypt_load(cd, CRYPT_LUKS2, NULL), "Device too small"); + NULL_(crypt_get_type(cd)); + crypt_free(cd); + + // 0 secs for encrypted data area + params.data_alignment = 8192; + params.data_device = NULL; + OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + crypt_free(cd); + // load should be ok + OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0), "Device too small"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // damaged header + OK_(_system("dd if=/dev/zero of=" DMDIR L_DEVICE_OK " bs=512 count=8 2>/dev/null", 1)); + OK_(_system("dd if=/dev/zero of=" DMDIR L_DEVICE_OK " bs=512 seek=32 count=8 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + FAIL_(crypt_load(cd, CRYPT_LUKS2, NULL), "Header not found"); + crypt_free(cd); + + // plain device + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + FAIL_(crypt_load(cd, CRYPT_PLAIN, NULL), "Can't load nonLUKS device type"); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, key, key_size, &pl_params)); + FAIL_(crypt_load(cd, CRYPT_LUKS2, NULL), "Can't load over nonLUKS device type"); + crypt_free(cd); + + //LUKSv2 device + OK_(crypt_init(&cd, DEVICE_4)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + crypt_free(cd); + OK_(crypt_init(&cd, DEVICE_4)); + crypt_set_iteration_time(cd, 0); /* invalid for argon2 pbkdf, ignored */ + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + crypt_free(cd); + + /* check load sets proper device type */ + OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + EQ_(strcmp(CRYPT_LUKS2, crypt_get_type(cd)), 0); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void Luks2HeaderBackup(void) +{ + struct crypt_device *cd; + struct crypt_pbkdf_type pbkdf = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha256", + .parallel_threads = 4, + .max_memory_kb = 1024, + .time_ms = 1 + }; + struct crypt_params_luks2 params = { + .pbkdf = &pbkdf, + .data_alignment = 8192, // 4M, data offset will be 4096 + .data_device = DEVICE_2, + .sector_size = 512 + }; + char key[128]; + int fd, ro = O_RDONLY; + + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + size_t key_size = strlen(mk_hex) / 2; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + uint64_t r_payload_offset; + + const char *passphrase = PASSPHRASE; + + crypt_decode_key(key, mk_hex, key_size); + + OK_(get_luks2_offsets(0, params.data_alignment, 0, 0, NULL, &r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1)); + + // create LUKS device and backup the header + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 7, key, key_size, passphrase, strlen(passphrase)), 7); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, key, key_size, passphrase, strlen(passphrase)), 0); + OK_(crypt_header_backup(cd, CRYPT_LUKS2, BACKUP_FILE)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // restore header from backup + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_header_restore(cd, CRYPT_LUKS2, BACKUP_FILE)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // exercise luksOpen using backup header in file + OK_(crypt_init(&cd, BACKUP_FILE)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + OK_(crypt_init(&cd, BACKUP_FILE)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // exercise luksOpen using backup header on block device + fd = crypt_loop_attach(&DEVICE_3, BACKUP_FILE, 0, 0, &ro); + close(fd); + OK_(fd < 0); + OK_(crypt_init(&cd, DEVICE_3)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, passphrase, strlen(passphrase), 0), 0); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + OK_(crypt_init(&cd, DEVICE_3)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_set_data_device(cd, DMDIR L_DEVICE_OK)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, 7, passphrase, strlen(passphrase), 0), 7); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void ResizeDeviceLuks2(void) +{ + struct crypt_device *cd; + struct crypt_pbkdf_type pbkdf = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha256", + .parallel_threads = 4, + .max_memory_kb = 1024, + .time_ms = 1 + }; + struct crypt_params_luks2 params = { + .pbkdf = &pbkdf, + .data_alignment = 8192, // 4M, data offset will be 4096 + .sector_size = 512 + }; + char key[128]; + + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + size_t key_size = strlen(mk_hex) / 2; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + uint64_t r_payload_offset, r_header_size, r_size; + + crypt_decode_key(key, mk_hex, key_size); + + // prepare env + OK_(get_luks2_offsets(0, params.data_alignment, 0, 0, NULL, &r_payload_offset)); + OK_(get_luks2_offsets(1, 0, 0, 0, &r_header_size, NULL)); + OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size)); + OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 1000)); + OK_(create_dmdevice_over_loop(L_DEVICE_0S, 1000)); + + // test header and encrypted payload all in one device + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + // disable loading VKs in kernel keyring (compatible mode) + OK_(crypt_volume_key_keyring(cd, 0)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + OK_(crypt_resize(cd, CDEVICE_1, 0)); + OK_(crypt_resize(cd, CDEVICE_1, 42)); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(42, r_size >> SECTOR_SHIFT); + OK_(crypt_resize(cd, CDEVICE_1, 0)); + // autodetect encrypted device area size + OK_(crypt_resize(cd, CDEVICE_1, 0)); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small"); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + params.data_alignment = 0; + params.data_device = DMDIR L_DEVICE_0S; + // test case for external header + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + OK_(crypt_resize(cd, CDEVICE_1, 666)); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(666, r_size >> SECTOR_SHIFT); + // autodetect encrypted device size + OK_(crypt_resize(cd, CDEVICE_1, 0)); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small"); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + +#ifdef KERNEL_KEYRING + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + // enable loading VKs in kernel keyring (default mode) + OK_(crypt_volume_key_keyring(cd, 1)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + // erase volume key from kernel keyring + if (t_dm_crypt_keyring_support()) + OK_(_drop_keyring_key(cd, 0)); + else + FAIL_(_drop_keyring_key(cd, 0), "key not found"); + // same size is ok + OK_(crypt_resize(cd, CDEVICE_1, 0)); + // kernel fails to find the volume key in keyring + if (t_dm_crypt_keyring_support()) + FAIL_(crypt_resize(cd, CDEVICE_1, 42), "Unable to find volume key in keyring"); + else + OK_(crypt_resize(cd, CDEVICE_1, 42)); + // test mode must not load vk in keyring + OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0)); + if (t_dm_crypt_keyring_support()) + FAIL_(crypt_resize(cd, CDEVICE_1, 44), "VK must be in keyring to perform resize"); + else + OK_(crypt_resize(cd, CDEVICE_1, 44)); + // reinstate the volume key in keyring + OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, CRYPT_ACTIVATE_KEYRING_KEY)); + OK_(crypt_resize(cd, CDEVICE_1, 43)); + if (!t_device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(43, r_size >> SECTOR_SHIFT); + crypt_free(cd); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + // check userspace gets hint volume key must be properly loaded in kernel keyring + if (t_dm_crypt_keyring_support()) + EQ_(crypt_resize(cd, CDEVICE_1, 0), -EPERM); + else + OK_(crypt_resize(cd, CDEVICE_1, 0)); + crypt_free(cd); + + // same as above for handles initialised by name + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + if (t_dm_crypt_keyring_support()) + EQ_(crypt_resize(cd, CDEVICE_1, 0), -EPERM); + else + OK_(crypt_resize(cd, CDEVICE_1, 0)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); +#endif + + _cleanup_dmdevices(); +} + +static void TokenActivationByKeyring(void) +{ +#ifdef KERNEL_KEYRING + key_serial_t kid, kid1; + struct crypt_device *cd; + + const char *cipher = "aes"; + const char *cipher_mode = "xts-plain64"; + + const struct crypt_token_params_luks2_keyring params = { + .key_description = KEY_DESC_TEST0 + }, params2 = { + .key_description = KEY_DESC_TEST1 + }; + + kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING); + if (kid < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // prepare the device + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_token_luks2_keyring_set(cd, 3, ¶ms), 3); + EQ_(crypt_token_assign_keyslot(cd, 3, 0), 3); + crypt_free(cd); + + // test thread keyring key in token 0 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 3, NULL, 0), 0); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 3, NULL, 0), "already open"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_PROCESS_KEYRING); + if (kid < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // add token 1 with process keyring key + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_token_json_set(cd, 3, NULL), 3); + EQ_(crypt_token_luks2_keyring_set(cd, 1, ¶ms), 1); + EQ_(crypt_token_assign_keyslot(cd, 1, 0), 1); + crypt_free(cd); + + // test process keyring key in token 1 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0), 0); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0), "already open"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + if (keyctl_unlink(kid, KEY_SPEC_PROCESS_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // create two tokens and let the cryptsetup unlock the volume with the valid one + kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING); + if (kid < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING); + if (kid1 < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_token_luks2_keyring_set(cd, 0, ¶ms), 0); + EQ_(crypt_token_assign_keyslot(cd, 0, 0), 0); + EQ_(crypt_token_luks2_keyring_set(cd, 1, ¶ms2), 1); + FAIL_(crypt_token_assign_keyslot(cd, 1, 1), "Keyslot 1 doesn't exist"); + crypt_set_iteration_time(cd, 1); + EQ_(crypt_keyslot_add_by_passphrase(cd, 1, PASSPHRASE, strlen(PASSPHRASE), PASSPHRASE1, strlen(PASSPHRASE1)), 1); + EQ_(crypt_token_assign_keyslot(cd, 1, 1), 1); + crypt_free(cd); + + // activate by specific token + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 0, NULL, 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // activate by any token with token 0 having absent pass from keyring + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, CRYPT_ANY_TOKEN, NULL, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING); + if (kid < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // replace pass for keyslot 0 making token 0 invalid + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_keyslot_destroy(cd, 0)); + crypt_set_iteration_time(cd, 1); + EQ_(crypt_keyslot_add_by_passphrase(cd, 0, PASSPHRASE1, strlen(PASSPHRASE1), PASSPHRASE1, strlen(PASSPHRASE1)), 0); + crypt_free(cd); + + // activate by any token with token 0 having wrong pass for keyslot 0 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, CRYPT_ANY_TOKEN, NULL, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // create new device, with two tokens: + // 1st token being invalid (missing key in keyring) + // 2nd token can activate keyslot 1 after failing to do so w/ keyslot 0 (wrong pass) + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_volume_key(cd, 1, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1)), 1); + EQ_(crypt_token_luks2_keyring_set(cd, 0, ¶ms), 0); + EQ_(crypt_token_assign_keyslot(cd, 0, 0), 0); + EQ_(crypt_token_luks2_keyring_set(cd, 2, ¶ms2), 2); + EQ_(crypt_token_assign_keyslot(cd, 2, 1), 2); + crypt_free(cd); + + if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING); + if (kid1 < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, CRYPT_ANY_TOKEN, NULL, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); +#else + printf("WARNING: cryptsetup compiled with kernel keyring service disabled, skipping test.\n"); +#endif +} + +static void Tokens(void) +{ +#define TEST_TOKEN_JSON(x) "{\"type\":\"test_token\",\"keyslots\":[" x "]," \ + "\"key_length\":32,\"a_field\":\"magic_string\"}" + +#define TEST_TOKEN_JSON_INVALID(x) "{\"type\":\"test_token\",\"keyslots\":[" x "]," \ + "\"key_length\":32}" + +#define TEST_TOKEN1_JSON(x) "{\"type\":\"test_token1\",\"keyslots\":[" x "]," \ + "\"key_length\":32,\"a_field\":\"magic_string\"}" + +#define TEST_TOKEN1_JSON_INVALID(x) "{\"type\":\"test_token1\",\"keyslots\":[" x "]," \ + "\"key_length\":32}" + +#define BOGUS_TOKEN0_JSON "{\"type\":\"luks2-\",\"keyslots\":[]}" +#define BOGUS_TOKEN1_JSON "{\"type\":\"luks2-a\",\"keyslots\":[]}" + + struct crypt_device *cd; + + const char *dummy; + const char *cipher = "aes"; + const char *cipher_mode = "xts-plain64"; + + static const crypt_token_handler th = { + .name = "test_token", + .open = test_open, + .validate = test_validate + }, th2 = { + .name = "test_token", + .open = test_open + }, th3 = { + .name = "test_token1", + .open = test_open, + .validate = test_validate + }, th_reserved = { + .name = "luks2-prefix", + .open = test_open + }; + + struct crypt_token_params_luks2_keyring params = { + .key_description = "desc" + }; + + OK_(crypt_token_register(&th)); + FAIL_(crypt_token_register(&th2), "Token handler with the name already registered."); + + FAIL_(crypt_token_register(&th_reserved), "luks2- is reserved prefix"); + + // basic token API tests + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + EQ_(crypt_token_status(cd, -1, NULL), CRYPT_TOKEN_INVALID); + EQ_(crypt_token_status(cd, 32, NULL), CRYPT_TOKEN_INVALID); + EQ_(crypt_token_status(cd, 0, NULL), CRYPT_TOKEN_INACTIVE); + EQ_(crypt_token_status(cd, 31, NULL), CRYPT_TOKEN_INACTIVE); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_volume_key(cd, 1, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1)), 1); + FAIL_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, TEST_TOKEN_JSON_INVALID("\"0\"")), "Token validation failed"); + EQ_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, TEST_TOKEN_JSON("\"0\"")), 0); + EQ_(crypt_token_status(cd, 0, NULL), CRYPT_TOKEN_EXTERNAL); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 0, PASSPHRASE, 0), 0); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 0, PASSPHRASE, 0), "already active"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + + // write invalid token and verify that validate() can detect it after handler being registered + EQ_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, TEST_TOKEN1_JSON_INVALID("\"1\"")), 1); + EQ_(crypt_token_status(cd, 1, NULL), CRYPT_TOKEN_EXTERNAL_UNKNOWN); + EQ_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, TEST_TOKEN1_JSON("\"1\"")), 2); + EQ_(crypt_token_status(cd, 2, &dummy), CRYPT_TOKEN_EXTERNAL_UNKNOWN); + OK_(strcmp(dummy, "test_token1")); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 1, PASSPHRASE1, 0), "Unknown token handler"); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE1, 0), "Unknown token handler"); + OK_(crypt_token_register(&th3)); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 1, PASSPHRASE1, 0), "Token validation failed"); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE1, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + + // test crypt_token_json_get returns correct token id + EQ_(crypt_token_json_get(cd, 2, &dummy), 2); + + // exercise assign/unassign keyslots API + EQ_(crypt_token_unassign_keyslot(cd, 2, 1), 2); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE1, 0), "Token assigned to no keyslot"); + EQ_(crypt_token_assign_keyslot(cd, 2, 0), 2); + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE1, 0), "Wrong passphrase"); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE, 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_token_json_set(cd, 1, NULL), 1); + FAIL_(crypt_token_json_get(cd, 1, &dummy), "Token is not there"); + EQ_(crypt_token_unassign_keyslot(cd, 2, CRYPT_ANY_SLOT), 2); + EQ_(crypt_token_unassign_keyslot(cd, 0, CRYPT_ANY_SLOT), 0); + + // various tests related to unassigned keyslot to volume segment + EQ_(crypt_keyslot_add_by_key(cd, 3, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 3); + EQ_(crypt_token_assign_keyslot(cd, 2, 0), 2); + EQ_(crypt_token_assign_keyslot(cd, 0, 3), 0); + + EQ_(crypt_activate_by_token(cd, NULL, 2, PASSPHRASE, 0), 0); + EQ_(crypt_activate_by_token(cd, NULL, 0, PASSPHRASE1, 0), 3); + // FIXME: useless error message here (or missing one to be specific) + FAIL_(crypt_activate_by_token(cd, CDEVICE_1, 0, PASSPHRASE1, 0), "No volume key available in token keyslots"); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE, 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_token_assign_keyslot(cd, 0, 1), 0); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 0, PASSPHRASE1, 0), 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + + EQ_(crypt_token_assign_keyslot(cd, 2, 3), 2); + EQ_(crypt_activate_by_token(cd, NULL, 2, PASSPHRASE, 0), 0); + EQ_(crypt_activate_by_token(cd, CDEVICE_1, 2, PASSPHRASE, 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + + EQ_(crypt_token_luks2_keyring_set(cd, 5, ¶ms), 5); + EQ_(crypt_token_status(cd, 5, &dummy), CRYPT_TOKEN_INTERNAL); + OK_(strcmp(dummy, "luks2-keyring")); + + FAIL_(crypt_token_luks2_keyring_get(cd, 2, ¶ms), "Token is not luks2-keyring type"); + + FAIL_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, BOGUS_TOKEN0_JSON), "luks2- reserved prefix."); + FAIL_(crypt_token_json_set(cd, CRYPT_ANY_TOKEN, BOGUS_TOKEN1_JSON), "luks2- reserved prefix."); + + crypt_free(cd); +} + +static void LuksConvert(void) +{ + struct crypt_device *cd; + uint64_t offset, r_payload_offset; + + const struct crypt_pbkdf_type argon = { + .type = CRYPT_KDF_ARGON2I, + .hash = "sha512", + .time_ms = 1, + .max_memory_kb = 1024, + .parallel_threads = 1 + }, pbkdf2 = { + .type = CRYPT_KDF_PBKDF2, + .hash = "sha1", + .time_ms = 1 + }; + + struct crypt_params_luks2 luks2 = { + .pbkdf = &pbkdf2, + .sector_size = 512 + }; + + const char *cipher = "aes"; + const char *cipher_mode = "xts-plain64"; + + // prepare the device + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, NULL, 32, NULL)); + offset = crypt_get_data_offset(cd); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_volume_key(cd, 7, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1)), 7); + crypt_free(cd); + + // convert LUKSv1 -> LUKSv2 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "format is already LUKSv1"); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0); + FAIL_(crypt_convert(cd, CRYPT_LUKS2, NULL), "device is active"); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS1)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS2)); + crypt_free(cd); + + // check result + OK_(crypt_init(&cd, DEVICE_1)); + FAIL_(crypt_load(cd, CRYPT_LUKS1, NULL), "wrong luks format"); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS2)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE1, strlen(PASSPHRASE1), 0), 7); + OK_(crypt_deactivate(cd, CDEVICE_1)); + FAIL_(crypt_convert(cd, CRYPT_LUKS2, NULL), "format is already LUKSv2"); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS2)); + crypt_free(cd); + + // convert LUKSv2 -> LUKSv1 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0); + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "device is active"); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS2)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS1)); + crypt_free(cd); + + // check result + OK_(crypt_init(&cd, DEVICE_1)); + FAIL_(crypt_load(cd, CRYPT_LUKS2, NULL), "wrong luks format"); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS1)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE1, strlen(PASSPHRASE1), 0), 7); + OK_(crypt_deactivate(cd, CDEVICE_1)); + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "format is already LUKSv1"); + OK_(strcmp(crypt_get_type(cd), CRYPT_LUKS1)); + crypt_free(cd); + + // exercice non-pbkdf2 LUKSv2 conversion + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + OK_(crypt_set_pbkdf_type(cd, &argon)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "Incompatible pbkdf with LUKSv1 format"); + crypt_free(cd); + + // exercice non LUKS1 compatible keyslot + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, &luks2)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_key(cd, 1, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 1); + // FIXME: following test fails as expected but for a different reason + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "Unassigned keyslots are incompatible with LUKSv1 format"); + crypt_free(cd); + + // exercice LUKSv2 conversion with single pbkdf2 keyslot being active + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + crypt_free(cd); + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + crypt_free(cd); + + // do not allow conversion on keyslot No > 7 + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, &luks2)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_volume_key(cd, 8, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1)), 8); + FAIL_(crypt_convert(cd, CRYPT_LUKS1, NULL), "Can't convert keyslot No 8"); + crypt_free(cd); + + // should be enough for both luks1 and luks2 devices with all vk lengths + OK_(get_luks2_offsets(1, 0, 0, 0, NULL, &r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1)); + + // do not allow conversion for legacy luks1 device (non-aligned keyslot offset) + OK_(_system("dd if=" CONV_DIR "/" CONV_L1_256_LEGACY " of=" DMDIR L_DEVICE_1S " bs=1M count=2 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + FAIL_(crypt_convert(cd, CRYPT_LUKS2, NULL), "Can't convert device with unaligned keyslot offset"); + crypt_free(cd); + + /* + * do not allow conversion on images if there's not enough space between + * last keyslot and data offset (should not happen on headers created + * with cryptsetup) + */ + OK_(_system("dd if=" CONV_DIR "/" CONV_L1_256_UNMOVABLE " of=" DMDIR L_DEVICE_1S " bs=1M count=2 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + FAIL_(crypt_convert(cd, CRYPT_LUKS2, NULL), "Can't convert device with unaligned keyslot offset"); + crypt_free(cd); + + // compat conversion tests + // LUKS1 -> LUKS2 + + // 128b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L1_128 " of=" DMDIR L_DEVICE_1S " bs=1M count=2 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 256b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L1_256 " of=" DMDIR L_DEVICE_1S " bs=1M count=2 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 512b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L1_512 " of=" DMDIR L_DEVICE_1S " bs=1M count=2 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // detached LUKS1 header conversion + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_128_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_128_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 256b key + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_256_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_256_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 512b key + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_512_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS2), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L1_512_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // LUKS2 -> LUKS1 + // 128b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_128 " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 128b all LUKS1 keyslots used + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_128_FULL " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + // 256b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_256 " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 256b all LUKS1 keyslots used + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_256_FULL " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + // 512b key + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_512 " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 512b all LUKS1 keyslots used + OK_(_system("dd if=" CONV_DIR "/" CONV_L2_512_FULL " of=" DMDIR L_DEVICE_1S " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_1S)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + // detached headers + // 128b + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_128_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_128_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 128b all LUKS1 keyslots used + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_128_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_128_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + // 256b key + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_256_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_256_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 256b all LUKS1 keyslots used + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_256_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_256_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + // 512b key + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_512_DET)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + offset = crypt_get_data_offset(cd); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_512_DET)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_get_data_offset(cd), offset); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + crypt_free(cd); + + // 512b all LUKS1 keyslots used + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_512_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + OK_(crypt_convert(cd, CRYPT_LUKS1, NULL)); + EQ_(strcmp(crypt_get_type(cd), CRYPT_LUKS1), 0); + crypt_free(cd); + OK_(crypt_init(&cd, CONV_DIR "/" CONV_L2_512_DET_FULL)); + OK_(crypt_load(cd, CRYPT_LUKS1, NULL)); + EQ_(crypt_activate_by_passphrase(cd, NULL, 0, PASS0, strlen(PASS0), 0), 0); + EQ_(crypt_activate_by_passphrase(cd, NULL, 7, PASS7, strlen(PASS7), 0), 7); + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASS1, strlen(PASS1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, 2, PASS2, strlen(PASS2), 0), 2); + EQ_(crypt_activate_by_passphrase(cd, NULL, 3, PASS3, strlen(PASS3), 0), 3); + EQ_(crypt_activate_by_passphrase(cd, NULL, 4, PASS4, strlen(PASS4), 0), 4); + EQ_(crypt_activate_by_passphrase(cd, NULL, 5, PASS5, strlen(PASS5), 0), 5); + EQ_(crypt_activate_by_passphrase(cd, NULL, 6, PASS6, strlen(PASS6), 0), 6); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void Pbkdf(void) +{ + struct crypt_device *cd; + const struct crypt_pbkdf_type *pbkdf; + + const char *cipher = "aes", *mode="xts-plain64"; + struct crypt_pbkdf_type argon2 = { + .type = CRYPT_KDF_ARGON2I, + .hash = DEFAULT_LUKS1_HASH, + .time_ms = 6, + .max_memory_kb = 1024, + .parallel_threads = 1 + }, pbkdf2 = { + .type = CRYPT_KDF_PBKDF2, + .hash = DEFAULT_LUKS1_HASH, + .time_ms = 9 + }, bad = { + .type = "hamster_pbkdf", + .hash = DEFAULT_LUKS1_HASH + }; + struct crypt_params_plain params = { + .hash = "sha1", + .skip = 0, + .offset = 0, + .size = 0 + }; + struct crypt_params_luks1 luks1 = { + .hash = "whirlpool", // test non-standard hash + .data_alignment = 2048, + }; + + // test empty context + OK_(crypt_init(&cd, DEVICE_1)); + NULL_(crypt_get_pbkdf_type(cd)); + OK_(crypt_set_pbkdf_type(cd, &argon2)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + OK_(crypt_set_pbkdf_type(cd, NULL)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + + // test plain device + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, mode, NULL, NULL, 32, ¶ms)); + OK_(crypt_set_pbkdf_type(cd, &argon2)); + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + OK_(crypt_set_pbkdf_type(cd, NULL)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + crypt_free(cd); + + // test LUKSv1 device + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, mode, NULL, NULL, 32, NULL)); + FAIL_(crypt_set_pbkdf_type(cd, &argon2), "Unsupported with non-LUKS2 devices"); + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + OK_(crypt_set_pbkdf_type(cd, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + EQ_(pbkdf->time_ms, DEFAULT_LUKS1_ITER_TIME); + crypt_free(cd); + // test value set in crypt_set_iteration_time() can be obtained via following crypt_get_pbkdf_type() + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 42); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, mode, NULL, NULL, 32, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + EQ_(pbkdf->time_ms, 42); + // test crypt_get_pbkdf_type() returns expected values for LUKSv1 + OK_(strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)); + OK_(strcmp(pbkdf->hash, DEFAULT_LUKS1_HASH)); + EQ_(pbkdf->max_memory_kb, 0); + EQ_(pbkdf->parallel_threads, 0); + crypt_set_iteration_time(cd, 43); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + EQ_(pbkdf->time_ms, 43); + crypt_free(cd); + // test whether crypt_get_pbkdf_type() after double crypt_load() + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + crypt_set_iteration_time(cd, 42); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + EQ_(pbkdf->time_ms, 42); + crypt_free(cd); + // test whether hash passed via *params in crypt_load() has higher priority + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, mode, NULL, NULL, 32, &luks1)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->hash, luks1.hash)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->hash, luks1.hash)); + crypt_free(cd); + + // test LUKSv2 device + // test default values are set + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, mode, NULL, NULL, 32, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, DEFAULT_LUKS2_PBKDF)); + OK_(strcmp(pbkdf->hash, DEFAULT_LUKS1_HASH)); + EQ_(pbkdf->time_ms, DEFAULT_LUKS2_ITER_TIME); + EQ_(pbkdf->max_memory_kb, DEFAULT_LUKS2_MEMORY_KB); + EQ_(pbkdf->parallel_threads, _min(cpus_online(), DEFAULT_LUKS2_PARALLEL_THREADS)); + // set and verify argon2 type + OK_(crypt_set_pbkdf_type(cd, &argon2)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, argon2.type)); + OK_(strcmp(pbkdf->hash, argon2.hash)); + EQ_(pbkdf->time_ms, argon2.time_ms); + EQ_(pbkdf->max_memory_kb, argon2.max_memory_kb); + EQ_(pbkdf->parallel_threads, argon2.parallel_threads); + // set and verify pbkdf2 type + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, pbkdf2.type)); + OK_(strcmp(pbkdf->hash, pbkdf2.hash)); + EQ_(pbkdf->time_ms, pbkdf2.time_ms); + EQ_(pbkdf->max_memory_kb, pbkdf2.max_memory_kb); + EQ_(pbkdf->parallel_threads, pbkdf2.parallel_threads); + // reset and verify default values + crypt_set_iteration_time(cd, 1); // it's supposed to override this call + OK_(crypt_set_pbkdf_type(cd, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, DEFAULT_LUKS2_PBKDF)); + OK_(strcmp(pbkdf->hash, DEFAULT_LUKS1_HASH)); + EQ_(pbkdf->time_ms, DEFAULT_LUKS2_ITER_TIME); + EQ_(pbkdf->max_memory_kb, DEFAULT_LUKS2_MEMORY_KB); + EQ_(pbkdf->parallel_threads, _min(cpus_online(), DEFAULT_LUKS2_PARALLEL_THREADS)); + // try to pass illegal values + argon2.parallel_threads = 0; + FAIL_(crypt_set_pbkdf_type(cd, &argon2), "Parallel threads can't be 0"); + argon2.parallel_threads = 1; + argon2.max_memory_kb = 0; + FAIL_(crypt_set_pbkdf_type(cd, &argon2), "Memory can't be 0"); + argon2.max_memory_kb = 1024; + pbkdf2.parallel_threads = 1; + FAIL_(crypt_set_pbkdf_type(cd, &pbkdf2), "Parallel threads can't be set with pbkdf2 type"); + pbkdf2.parallel_threads = 0; + pbkdf2.max_memory_kb = 512; + FAIL_(crypt_set_pbkdf_type(cd, &pbkdf2), "Memory can't be set with pbkdf2 type"); + FAIL_(crypt_set_pbkdf_type(cd, &bad), "Unknown type member"); + bad.type = CRYPT_KDF_PBKDF2; + bad.hash = NULL; + FAIL_(crypt_set_pbkdf_type(cd, &bad), "Hash member is empty"); + bad.type = NULL; + bad.hash = DEFAULT_LUKS1_HASH; + FAIL_(crypt_set_pbkdf_type(cd, &bad), "Pbkdf type member is empty"); + // following test fails atm + // bad.hash = "hamster_hash"; + // FAIL_(crypt_set_pbkdf_type(cd, &pbkdf2), "Unknown hash member"); + crypt_free(cd); + // test whether crypt_get_pbkdf_type() behaves accordinglt after second crypt_load() call + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, DEFAULT_LUKS2_PBKDF)); + OK_(strcmp(pbkdf->hash, DEFAULT_LUKS1_HASH)); + EQ_(pbkdf->time_ms, DEFAULT_LUKS2_ITER_TIME); + EQ_(pbkdf->max_memory_kb, DEFAULT_LUKS2_MEMORY_KB); + EQ_(pbkdf->parallel_threads, _min(cpus_online(), DEFAULT_LUKS2_PARALLEL_THREADS)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + OK_(strcmp(pbkdf->type, DEFAULT_LUKS2_PBKDF)); + OK_(strcmp(pbkdf->hash, DEFAULT_LUKS1_HASH)); + EQ_(pbkdf->time_ms, 1); + EQ_(pbkdf->max_memory_kb, DEFAULT_LUKS2_MEMORY_KB); + EQ_(pbkdf->parallel_threads, _min(cpus_online(), DEFAULT_LUKS2_PARALLEL_THREADS)); + crypt_free(cd); + + // test crypt_set_pbkdf_type() overwrites invalid value set by crypt_set_iteration_time() + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 0); + OK_(crypt_set_pbkdf_type(cd, &argon2)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + OK_(strcmp(pbkdf->type, argon2.type)); + EQ_(pbkdf->time_ms, argon2.time_ms); + + // force iterations + argon2.iterations = 33; + argon2.flags = CRYPT_PBKDF_NO_BENCHMARK; + OK_(crypt_set_pbkdf_type(cd, &argon2)); + NOTNULL_(pbkdf = crypt_get_pbkdf_type(cd)); + EQ_(pbkdf->iterations, 33); + EQ_(pbkdf->flags, CRYPT_PBKDF_NO_BENCHMARK); + + crypt_free(cd); +} + +static void Luks2KeyslotAdd(void) +{ + char key[128], key2[128]; + struct crypt_device *cd; + const char *cipher = "aes", *cipher_mode="xts-plain64"; + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e"; + size_t key_size = strlen(mk_hex) / 2; + + crypt_decode_key(key, mk_hex, key_size); + crypt_decode_key(key2, mk_hex2, key_size); + + /* test crypt_keyslot_add_by_key */ + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, key, key_size, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, key_size, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_key(cd, 1, key2, key_size, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 1); + EQ_(crypt_keyslot_status(cd, 0), CRYPT_SLOT_ACTIVE_LAST); + EQ_(crypt_keyslot_status(cd, 1), CRYPT_SLOT_ACTIVE); + /* must not activate volume with keyslot unassigned to a segment */ + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_1, key2, key_size, 0), "Key doesn't match volume key digest"); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, 1, PASSPHRASE1, strlen(PASSPHRASE1), 0), "Keyslot not assigned to volume"); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE1, strlen(PASSPHRASE1), 0), "No keyslot assigned to volume with this passphrase"); + /* unusable for volume activation even in test mode */ + FAIL_(crypt_activate_by_volume_key(cd, NULL, key2, key_size, 0), "Key doesn't match volume key digest"); + /* otoh passphrase check should pass */ + EQ_(crypt_activate_by_passphrase(cd, NULL, 1, PASSPHRASE1, strlen(PASSPHRASE1), 0), 1); + EQ_(crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, PASSPHRASE1, strlen(PASSPHRASE1), 0), 1); + crypt_free(cd); +} + +static void Luks2ActivateByKeyring(void) +{ +#ifdef KERNEL_KEYRING + + key_serial_t kid, kid1; + struct crypt_device *cd; + + const char *cipher = "aes"; + const char *cipher_mode = "xts-plain64"; + + kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING); + kid1 = add_key("user", KEY_DESC_TEST1, PASSPHRASE1, strlen(PASSPHRASE1), KEY_SPEC_THREAD_KEYRING); + if (kid < 0 || kid1 < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + // prepare the device + OK_(crypt_init(&cd, DEVICE_1)); + crypt_set_iteration_time(cd, 1); + OK_(crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, 32, NULL)); + EQ_(crypt_keyslot_add_by_volume_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE)), 0); + EQ_(crypt_keyslot_add_by_key(cd, 1, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 1); + EQ_(crypt_keyslot_add_by_volume_key(cd, 2, NULL, 32, PASSPHRASE1, strlen(PASSPHRASE1)), 2); + crypt_free(cd); + + // FIXME: all following tests work as expected but most error messages are missing + // check activate by keyring works exactly same as by passphrase + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + EQ_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, 0), 0); + EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0), 0); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0), "already open"); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + EQ_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 1, 0), 1); + EQ_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 2, 0), 2); + FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, 1, 0), "Keyslot not assigned to volume"); + EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, 2, 0), 2); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, CRYPT_ANY_SLOT, 0), 2); + OK_(crypt_deactivate(cd, CDEVICE_1)); + FAIL_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 2, 0), "Failed to unclock keyslot"); + FAIL_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 0, 0), "Failed to unclock keyslot"); + crypt_free(cd); + + if (keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + if (keyctl_unlink(kid1, KEY_SPEC_THREAD_KEYRING)) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + FAIL_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, CRYPT_ANY_SLOT, 0), "no such key in keyring"); + FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, CRYPT_ANY_SLOT, 0), "no such key in keyring"); + FAIL_(crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST1, 2, 0), "no such key in keyring"); + FAIL_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST1, 1, 0), "no such key in keyring"); + crypt_free(cd); +#else + printf("WARNING: cryptsetup compiled with kernel keyring service disabled, skipping test.\n"); +#endif +} + +static void Luks2Requirements(void) +{ + int r; + struct crypt_device *cd; + char key[128]; + size_t key_size = 128; + const struct crypt_pbkdf_type *pbkdf; +#ifdef KERNEL_KEYRING + key_serial_t kid; +#endif + uint32_t flags; + uint64_t dummy, r_payload_offset; + struct crypt_active_device cad; + + const char *token, *json = "{\"type\":\"test_token\",\"keyslots\":[]}"; + struct crypt_pbkdf_type argon2 = { + .type = CRYPT_KDF_ARGON2I, + .hash = DEFAULT_LUKS1_HASH, + .time_ms = 6, + .max_memory_kb = 1024, + .parallel_threads = 1 + }, pbkdf2 = { + .type = CRYPT_KDF_PBKDF2, + .hash = DEFAULT_LUKS1_HASH, + .time_ms = 9 + }; + struct crypt_token_params_luks2_keyring params_get, params = { + .key_description = KEY_DESC_TEST0 + }; + + OK_(prepare_keyfile(KEYFILE1, "aaa", 3)); + OK_(prepare_keyfile(KEYFILE2, "xxx", 3)); + + /* crypt_load (unrestricted) */ + OK_(crypt_init(&cd, DEVICE_5)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + crypt_free(cd); + + OK_(crypt_init(&cd, DEVICE_5)); + OK_(crypt_load(cd, CRYPT_LUKS2, NULL)); + + /* crypt_dump (unrestricted) */ + reset_log(); + OK_(crypt_dump(cd)); + OK_(!(global_lines != 0)); + reset_log(); + + /* get & set pbkdf params (unrestricted) */ + OK_(crypt_set_pbkdf_type(cd, &argon2)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + OK_(crypt_set_pbkdf_type(cd, &pbkdf2)); + NOTNULL_(crypt_get_pbkdf_type(cd)); + + /* crypt_set_itertion_time (unrestricted) */ + crypt_set_iteration_time(cd, 1); + pbkdf = crypt_get_pbkdf_type(cd); + NOTNULL_(pbkdf); + EQ_(pbkdf->time_ms, 1); + + /* crypt_convert (restricted) */ + FAIL_((r = crypt_convert(cd, CRYPT_LUKS1, NULL)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_set_uuid (restricted) */ + FAIL_((r = crypt_set_uuid(cd, NULL)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_set_label (restricted) */ + FAIL_((r = crypt_set_label(cd, "label", "subsystem")), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_repair (not implemented for luks2) */ + FAIL_(crypt_repair(cd, CRYPT_LUKS2, NULL), "Not implemented"); + + /* crypt_keyslot_add_passphrase (restricted) */ + FAIL_((r = crypt_keyslot_add_by_passphrase(cd, CRYPT_ANY_SLOT, "aaa", 3, "bbb", 3)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_change_by_passphrase (restricted) */ + FAIL_((r = crypt_keyslot_change_by_passphrase(cd, CRYPT_ANY_SLOT, 9, "aaa", 3, "bbb", 3)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_add_by_keyfile (restricted) */ + FAIL_((r = crypt_keyslot_add_by_keyfile(cd, CRYPT_ANY_SLOT, KEYFILE1, 0, KEYFILE2, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_add_by_keyfile_offset (restricted) */ + FAIL_((r = crypt_keyslot_add_by_keyfile_offset(cd, CRYPT_ANY_SLOT, KEYFILE1, 0, 0, KEYFILE2, 0, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_volume_key_get (unrestricted, but see below) */ + /* FIXME: eventual fips requirement should stop this */ + if (!_fips_mode) + OK_(crypt_volume_key_get(cd, 0, key, &key_size, "aaa", 3)); + + /* crypt_keyslot_add_by_volume_key (restricted) */ + FAIL_((r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, key, key_size, "xxx", 3)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_add_by_key (restricted) */ + FAIL_((r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, NULL, key_size, "xxx", 3, CRYPT_VOLUME_KEY_NO_SEGMENT)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_add_by_key (restricted) */ + FAIL_((r = crypt_keyslot_add_by_key(cd, CRYPT_ANY_SLOT, key, key_size, "xxx", 3, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_persistent_flasgs_set (restricted) */ + FAIL_((r = crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, CRYPT_ACTIVATE_ALLOW_DISCARDS)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_persistent_flasgs_get (unrestricted) */ + OK_(crypt_persistent_flags_get(cd, CRYPT_FLAGS_REQUIREMENTS, &flags)); + EQ_(flags, (uint32_t) CRYPT_REQUIREMENT_UNKNOWN); + + /* crypt_activate_by_passphrase (restricted for activation only) */ + FAIL_((r = crypt_activate_by_passphrase(cd, CDEVICE_1, 0, "aaa", 3, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + OK_(crypt_activate_by_passphrase(cd, NULL, 0, "aaa", 3, 0)); + OK_(crypt_activate_by_passphrase(cd, NULL, 0, "aaa", 3, CRYPT_ACTIVATE_KEYRING_KEY)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + + /* crypt_activate_by_keyfile (restricted for activation only) */ + FAIL_((r = crypt_activate_by_keyfile(cd, CDEVICE_1, 0, KEYFILE1, 0, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + OK_(crypt_activate_by_keyfile(cd, NULL, 0, KEYFILE1, 0, 0)); + OK_(crypt_activate_by_keyfile(cd, NULL, 0, KEYFILE1, 0, CRYPT_ACTIVATE_KEYRING_KEY)); + + /* crypt_activate_by_volume_key (restricted for activation only) */ + FAIL_((r = crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0)); + OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, CRYPT_ACTIVATE_KEYRING_KEY)); + +#ifdef KERNEL_KEYRING + kid = add_key("user", KEY_DESC_TEST0, "aaa", 3, KEY_SPEC_THREAD_KEYRING); + if (kid < 0) { + printf("Test or kernel keyring are broken.\n"); + exit(1); + } + + /* crypt_activate_by_keyring (restricted for activation only) */ + FAIL_((r = crypt_activate_by_keyring(cd, CDEVICE_1, KEY_DESC_TEST0, 0, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, 0)); + OK_(crypt_activate_by_keyring(cd, NULL, KEY_DESC_TEST0, 0, CRYPT_ACTIVATE_KEYRING_KEY)); +#endif + + /* crypt_volume_key_verify (unrestricted) */ + OK_(crypt_volume_key_verify(cd, key, key_size)); + + /* crypt_get_cipher (unrestricted) */ + OK_(strcmp(crypt_get_cipher(cd)?:"", "aes")); + + /* crypt_get_cipher_mode (unrestricted) */ + OK_(strcmp(crypt_get_cipher_mode(cd)?:"", "xts-plain64")); + + /* crypt_get_uuid (unrestricted) */ + NOTNULL_(crypt_get_uuid(cd)); + + /* crypt_get_device_name (unrestricted) */ + NOTNULL_(crypt_get_device_name(cd)); + + /* crypt_get_data_offset (unrestricted) */ + OK_(!crypt_get_data_offset(cd)); + + /* crypt_get_iv_offset (unrestricted, nothing to test) */ + + /* crypt_get_volume_key_size (unrestricted) */ + EQ_(crypt_get_volume_key_size(cd), key_size); + + /* crypt_keyslot_status (unrestricted) */ + EQ_(crypt_keyslot_status(cd, 0), CRYPT_SLOT_ACTIVE_LAST); + EQ_(crypt_keyslot_status(cd, 1), CRYPT_SLOT_INACTIVE); + + /* crypt_keyslot_get_priority (unrestricted) */ + EQ_(crypt_keyslot_get_priority(cd, 0), CRYPT_SLOT_PRIORITY_NORMAL); + + /* crypt_keyslot_set_priority (restricted) */ + FAIL_((r = crypt_keyslot_set_priority(cd, 0, CRYPT_SLOT_PRIORITY_PREFER)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_keyslot_area (unrestricted) */ + OK_(crypt_keyslot_area(cd, 0, &dummy, &dummy)); + OK_(!dummy); + + /* crypt_header_backup (unrestricted) */ + remove(BACKUP_FILE); + OK_(crypt_header_backup(cd, CRYPT_LUKS, BACKUP_FILE)); + + /* crypt_header_restore (restricted, do not drop the test untill we have safe option) */ + FAIL_((r = crypt_header_restore(cd, CRYPT_LUKS2, BACKUP_FILE)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + remove(BACKUP_FILE); + + /* crypt_token_json_set (restricted) */ + FAIL_((r = crypt_token_json_set(cd, CRYPT_ANY_TOKEN, json)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_token_json_get (unrestricted) */ + OK_(crypt_token_json_get(cd, 0, &token)); + NOTNULL_(strstr(token, "user_type")); + + /* crypt_token_status (unrestricted) */ + EQ_(crypt_token_status(cd, 0, &token), CRYPT_TOKEN_EXTERNAL_UNKNOWN); + OK_(strcmp(token, "user_type")); + EQ_(crypt_token_status(cd, 1, &token), CRYPT_TOKEN_INTERNAL); + OK_(strcmp(token, "luks2-keyring")); + EQ_(crypt_token_status(cd, 2, NULL), CRYPT_TOKEN_INACTIVE); + EQ_(crypt_token_status(cd, 6, &token), CRYPT_TOKEN_INTERNAL_UNKNOWN); + + /* crypt_token_luks2_keyring_set (restricted) */ + FAIL_((r = crypt_token_luks2_keyring_set(cd, CRYPT_ANY_TOKEN, ¶ms)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_token_luks2_keyring_get (unrestricted) */ + EQ_(crypt_token_luks2_keyring_get(cd, 1, ¶ms_get), 1); + OK_(strcmp(params_get.key_description, KEY_DESC_TEST0)); + + /* crypt_token_assign_keyslot (unrestricted) */ + FAIL_((r = crypt_token_assign_keyslot(cd, 0, 1)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_token_unassign_keyslot (unrestricted) */ + FAIL_((r = crypt_token_unassign_keyslot(cd, CRYPT_ANY_TOKEN, CRYPT_ANY_SLOT)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_activate_by_token (restricted for activation only) */ + FAIL_((r = crypt_activate_by_token(cd, CDEVICE_1, 1, NULL, 0)), ""); // supposed to be silent + EQ_(r, -ETXTBSY); +#ifdef KERNEL_KEYRING + OK_(crypt_activate_by_token(cd, NULL, 1, NULL, 0)); + OK_(crypt_activate_by_token(cd, NULL, 1, NULL, CRYPT_ACTIVATE_KEYRING_KEY)); +#endif + OK_(get_luks2_offsets(1, 8192, 0, 0, NULL, &r_payload_offset)); + OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_payload_offset + 2)); + //OK_(_system("dd if=" NO_REQS_LUKS2_HEADER " of=" NO_REQS_LUKS2_HEADER " bs=4096 2>/dev/null", 1)); + OK_(_system("dd if=" NO_REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + + /* need to fake activated LUKSv2 device with requirements features */ + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_load(cd, CRYPT_LUKS, NULL)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, 0, "aaa", 3, 0)); + OK_(crypt_header_backup(cd, CRYPT_LUKS2, BACKUP_FILE)); + /* replace header with no requirements */ + OK_(_system("dd if=" REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + crypt_free(cd); + + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DEVICE_5)); + crypt_free(cd); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + + /* crypt_header_restore (restricted with confirmation required) */ + /* allow force restore over device header w/ requirements */ + OK_(crypt_header_restore(cd, CRYPT_LUKS2, BACKUP_FILE)); + remove(BACKUP_FILE); + OK_(_system("dd if=" REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_header_backup(cd, CRYPT_LUKS2, BACKUP_FILE)); /* create backup with requirements */ + + /* crypt_suspend (restricted) */ + FAIL_((r = crypt_suspend(cd, CDEVICE_1)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + crypt_free(cd); + + /* replace header again to suspend the device */ + OK_(_system("dd if=" NO_REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(crypt_suspend(cd, CDEVICE_1)); + + /* crypt_header_restore (restricted, do not drop the test untill we have safe option) */ + /* refuse to overwrite header w/ backup including requirements */ + FAIL_((r = crypt_header_restore(cd, CRYPT_LUKS2, BACKUP_FILE)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + crypt_free(cd); + + OK_(_system("dd if=" REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + + /* crypt_resume_by_passphrase (restricted) */ + FAIL_((r = crypt_resume_by_passphrase(cd, CDEVICE_1, 0, "aaa", 3)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_resume_by_keyfile (restricted) */ + FAIL_((r = crypt_resume_by_keyfile(cd, CDEVICE_1, 0, KEYFILE1, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + + /* crypt_resume_by_keyfile_offset (restricted) */ + FAIL_((r = crypt_resume_by_keyfile_offset(cd, CDEVICE_1, 0, KEYFILE1, 0, 0)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + crypt_free(cd); + + OK_(_system("dd if=" NO_REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(crypt_resume_by_passphrase(cd, CDEVICE_1, 0, "aaa", 3)); + crypt_free(cd); + OK_(_system("dd if=" REQS_LUKS2_HEADER " of=" DMDIR L_DEVICE_OK " bs=1M count=4 oflag=direct 2>/dev/null", 1)); + + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + /* load VK in keyring */ + OK_(crypt_activate_by_passphrase(cd, NULL, 0, "aaa", 3, CRYPT_ACTIVATE_KEYRING_KEY)); + /* crypt_resize (restricted) */ + FAIL_((r = crypt_resize(cd, CDEVICE_1, 1)), "Unmet requirements detected"); + EQ_(r, -ETXTBSY); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + + /* crypt_get_active_device (unrestricted) */ + OK_(crypt_get_active_device(cd, CDEVICE_1, &cad)); +#ifdef KERNEL_KEYRING + if (t_dm_crypt_keyring_support()) + EQ_(cad.flags & CRYPT_ACTIVATE_KEYRING_KEY, CRYPT_ACTIVATE_KEYRING_KEY); +#endif + + /* crypt_deactivate (unrestricted) */ + OK_(crypt_deactivate(cd, CDEVICE_1)); + + /* crypt_keyslot_destroy (unrestricted) */ + OK_(crypt_keyslot_destroy(cd, 0)); + + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void Luks2Integrity(void) +{ + struct crypt_device *cd; + struct crypt_params_integrity ip = {}; + struct crypt_params_luks2 params = { + .sector_size = 512, + .integrity = "hmac(sha256)" + }; + size_t key_size = 32 + 32; + const char *passphrase = "blabla"; + const char *cipher = "aes"; + const char *cipher_mode = "xts-random"; + int ret; + + // FIXME: This is just a stub + OK_(crypt_init(&cd, DEVICE_2)); + ret = crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode, NULL, NULL, key_size, ¶ms); + if (ret < 0) { + printf("WARNING: cannot format integrity device, skipping test.\n"); + crypt_free(cd); + return; + } + + EQ_(crypt_keyslot_add_by_volume_key(cd, 7, NULL, key_size, passphrase, strlen(passphrase)), 7); + EQ_(crypt_activate_by_passphrase(cd, CDEVICE_2, 7, passphrase, strlen(passphrase) ,0), 7); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE); + crypt_free(cd); + + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_2, NULL)); + OK_(crypt_get_integrity_info(cd, &ip)); + OK_(strcmp(cipher, crypt_get_cipher(cd))); + OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); + OK_(strcmp("hmac(sha256)", ip.integrity)); + EQ_(32, ip.integrity_key_size); + EQ_(32+16, ip.tag_size); + OK_(crypt_deactivate(cd, CDEVICE_2)); + crypt_free(cd); +} + +static void int_handler(int sig __attribute__((__unused__))) +{ + _quit++; +} + +int main(int argc, char *argv[]) +{ + struct sigaction sa = { .sa_handler = int_handler }; + int i; + + if (getuid() != 0) { + printf("You must be root to run this test.\n"); + exit(77); + } + + for (i = 1; i < argc; i++) { + if (!strcmp("-v", argv[i]) || !strcmp("--verbose", argv[i])) + _verbose = 1; + else if (!strcmp("--debug", argv[i])) + _debug = _verbose = 1; + } + + /* Handle interrupt properly */ + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + register_cleanup(_cleanup); + + _cleanup(); + if (_setup()) + goto out; + + crypt_set_debug_level(_debug ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE); + + RUN_(AddDeviceLuks2, "Format and use LUKS2 device"); + RUN_(Luks2HeaderLoad, "test header load"); + RUN_(Luks2HeaderRestore, "test LUKS2 header restore"); + RUN_(Luks2HeaderBackup, "test LUKS2 header backup"); + RUN_(ResizeDeviceLuks2, "Luks device resize tests"); + RUN_(UseLuks2Device, "Use pre-formated LUKS2 device"); + RUN_(SuspendDevice, "Suspend/Resume test"); + RUN_(UseTempVolumes, "Format and use temporary encrypted device"); + RUN_(Tokens, "General tokens API tests"); + RUN_(TokenActivationByKeyring, "Builtin kernel keyring token tests"); + RUN_(LuksConvert, "Test LUKS1 <-> LUKS2 conversions"); + RUN_(Pbkdf, "Exercice default pbkdf manipulation routines"); + RUN_(Luks2KeyslotAdd, "Add new keyslot by unused key"); + RUN_(Luks2ActivateByKeyring, "Test LUKS2 activation by passphrase in keyring"); + RUN_(Luks2Requirements, "Test LUKS2 requirements flags"); + RUN_(Luks2Integrity, "Test LUKS2 with data integrity"); +out: + _cleanup(); + return 0; +} diff --git a/tests/api-test.c b/tests/api-test.c index 067d7bf2..824e6340 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -1,8 +1,9 @@ /* * cryptsetup library API check functions * - * Copyright (C) 2009-2013 Red Hat, Inc. All rights reserved. - * Copyright (C) 2009-2014, Milan Broz + * Copyright (C) 2009-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2009-2017, Milan Broz + * Copyright (C) 2016-2017, Ondrej Kozina * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/tests/api_test.h b/tests/api_test.h index 28531279..583f3480 100644 --- a/tests/api_test.h +++ b/tests/api_test.h @@ -2,7 +2,8 @@ * cryptsetup library API check functions * * Copyright (C) 2009-2017 Red Hat, Inc. All rights reserved. - * Copyright (C) 2009-2014, Milan Broz + * Copyright (C) 2009-2017, Milan Broz + * Copyright (C) 2016-2017, Ondrej Kozina * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/tests/compat-test b/tests/compat-test index 33dfec1b..a3c0b919 100755 --- a/tests/compat-test +++ b/tests/compat-test @@ -62,7 +62,7 @@ function fail() { [ -n "$1" ] && echo "$1" remove_mapping - echo "FAILED" + echo "FAILED at line $(caller)" exit 2 } diff --git a/tests/compat-test2 b/tests/compat-test2 new file mode 100755 index 00000000..c85475ad --- /dev/null +++ b/tests/compat-test2 @@ -0,0 +1,743 @@ +#!/bin/bash + +PS4='$LINENO:' +CRYPTSETUP=../src/cryptsetup + +CRYPTSETUP_VALGRIND=../src/.libs/cryptsetup +CRYPTSETUP_LIB_VALGRIND=../lib/.libs + +DEV_NAME=dummy +DEV_NAME2=dummy2 +DEV_NAME3=dummy3 +ORIG_IMG=luks-test-orig +IMG=luks-test +IMG10=luks-test-v10 +HEADER_IMG=luks-header +HEADER_KEYU=luks2_keyslot_unassigned.img +KEY1=key1 +KEY2=key2 +KEY5=key5 +KEYE=keye +PWD0="compatkey" +PWD1="93R4P4pIqAH8" +PWD2="mymJeD8ivEhE" +PWD3="ocMakf3fAcQO" +PWDW="rUkL4RUryBom" +CHKS_DMCRYPT=vk_in_dmcrypt.chk +CHKS_KEYRING=vk_in_keyring.chk +TEST_KEYRING_NAME="compattest2_keyring" +TEST_TOKEN0="compattest2_desc0" +TEST_TOKEN1="compattest2_desc1" + +FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" + +TEST_UUID="12345678-1234-1234-1234-123456789abc" + +LOOPDEV=$(losetup -f 2>/dev/null) +[ -f /etc/system-fips ] && FIPS_MODE=$(cat /proc/sys/crypto/fips_enabled 2>/dev/null) + +LOCK_DIR=$(grep DEFAULT_LUKS2_LOCK_PATH ../config.h | cut -d\" -f 2) +HAVE_KEYRING=$(grep -e "#define KERNEL_KEYRING" ../config.h) +test -n "$HAVE_KEYRING" || HAVE_KEYRING=0 +HAVE_KEYRING=${HAVE_KEYRING: -1} + +function remove_mapping() +{ + [ -b /dev/mapper/$DEV_NAME3 ] && dmsetup remove $DEV_NAME3 + [ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove $DEV_NAME2 + [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME + losetup -d $LOOPDEV >/dev/null 2>&1 + rm -f $ORIG_IMG $IMG $IMG10 $KEY1 $KEY2 $KEY5 $KEYE $HEADER_IMG $CHKS_DMCRYPT $CHKS_KEYRING $HEADER_KEYU >/dev/null 2>&1 + + # unlink whole test keyring + [ -n "$TEST_KEYRING" ] && keyctl unlink $TEST_KEYRING "@u" >/dev/null + unset TEST_KEYRING +} + +function force_uevent() +{ + DNAME=$(echo $LOOPDEV | cut -f3 -d /) + echo "change" >/sys/block/$DNAME/uevent +} + +function fail() +{ + [ -n "$1" ] && echo "$1" + remove_mapping + echo "FAILED at line $(caller)" + exit 2 +} + +function can_fail_fips() +{ + # Ignore this fail if running in FIPS mode + [ -z "$FIPS_MODE" -o "$FIPS_MODE" -eq 0 ] && fail $1 +} + +function skip() +{ + [ -n "$1" ] && echo "$1" + remove_mapping + exit 77 +} + +function prepare() +{ + [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME + + case "$2" in + wipe) + remove_mapping + dd if=/dev/zero of=$IMG bs=1k count=10000 >/dev/null 2>&1 + sync + losetup $LOOPDEV $IMG + ;; + new) + remove_mapping + bzip2 -cd compatimage.img.bz2 > $IMG + xz -dk $HEADER_KEYU.xz + # FIXME: switch to internal loop (no losetup at all) + echo "bad" | $CRYPTSETUP luksOpen --key-slot 0 --test-passphrase $IMG 2>&1 | \ + grep "autoclear flag" && skip "WARNING: Too old kernel, test skipped." + losetup $LOOPDEV $IMG + bzip2 -cd compatv10image.img.bz2 > $IMG10 + ;; + reuse | *) + if [ ! -e $IMG ]; then + bzip2 -cd compatimage.img.bz2 > $IMG + losetup $LOOPDEV $IMG + fi + [ ! -e $IMG10 ] && bzip2 -cd compatv10image.img.bz2 > $IMG10 + ;; + esac + + if [ ! -e $KEY1 ]; then + dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1 + fi + + if [ ! -e $KEY2 ]; then + dd if=/dev/urandom of=$KEY2 count=1 bs=16 >/dev/null 2>&1 + fi + + if [ ! -e $KEY5 ]; then + dd if=/dev/urandom of=$KEY5 count=1 bs=16 >/dev/null 2>&1 + fi + + if [ ! -e $KEYE ]; then + touch $KEYE + fi + + cp $IMG $ORIG_IMG + [ -n "$1" ] && echo "CASE: $1" +} + +function check_exists() +{ + [ -b /dev/mapper/$DEV_NAME ] || fail +} + +function valgrind_setup() +{ + which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind." + [ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable." + export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH" +} + +function valgrind_run() +{ + INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@" +} + +function dm_crypt_keyring_support() +{ + VER_STR=$(dmsetup targets | grep crypt | cut -f2 -dv) + [ -z "$VER_STR" ] && fail "Failed to parse dm-crypt version." + + VER_MAJ=$(echo $VER_STR | cut -f 1 -d.) + VER_MIN=$(echo $VER_STR | cut -f 2 -d.) + + [ $VER_MAJ -gt 1 ] && return 0 + [ $VER_MAJ -lt 1 ] && return 1 + [ $VER_MIN -ge 15 ] +} + +function test_and_prepare_keyring() { + which keyctl > /dev/null || skip "Cannot find keyctl, test skipped" + keyctl list "@s" > /dev/null || skip "Current session keyring is unreachable, test skipped" + TEST_KEYRING=$(keyctl newring $TEST_KEYRING_NAME "@u" 2> /dev/null) + test -n "$TEST_KEYRING" || skip "Failed to create keyring in user keyring" + keyctl search "@s" keyring "$TEST_KEYRING" > /dev/null 2>&1 || keyctl link "@u" "@s" > /dev/null 2>&1 + load_key user test_key test_data "$TEST_KEYRING" || skip "Kernel keyring service is useless on this system, test skipped." +} + +# $1 type +# $2 description +# $3 payload +# $4 keyring +function load_key() +{ + keyctl add $@ >/dev/null +} + +[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run + +[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." +[ -z "$LOOPDEV" ] && skip "WARNING: Cannot find free loop device, test skipped." +[ -d "$LOCK_DIR" ] || skip "WARNING: LUKS2 locking directory ($LOCK_DIR) is missing, test skipped." + +# LUKS tests +prepare "[3] format" new +echo $PWD1 | $CRYPTSETUP $FAST_PBKDF_OPT -c aes-cbc-essiv:sha256 -s 128 luksFormat --type luks2 $LOOPDEV || fail +prepare "[4] format using hash sha512" wipe +echo $PWD1 | $CRYPTSETUP $FAST_PBKDF_OPT -h sha512 -c aes-cbc-essiv:sha256 -s 128 luksFormat --type luks2 $LOOPDEV || fail + +prepare "[5] open" +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME --test-passphrase || fail +echo $PWDW | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME --test-passphrase 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail +check_exists + +# Key Slot 1 and key material section 1 must change, the rest must not. +prepare "[6] add key" +echo -e "$PWD1\n$PWD2" | $CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT || fail +echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail + +# Unsuccessful Key Delete - nothing may change +prepare "[7] unsuccessful delete" +echo $PWDW | $CRYPTSETUP luksKillSlot $LOOPDEV 1 2>/dev/null && fail +#FIXME +#$CRYPTSETUP -q luksKillSlot $LOOPDEV 8 2>/dev/null && fail +#$CRYPTSETUP -q luksKillSlot $LOOPDEV 7 2>/dev/null && fail + +# Delete Key Test +# Key Slot 1 and key material section 1 must change, the rest must not +prepare "[8] successful delete" +$CRYPTSETUP -q luksKillSlot $LOOPDEV 1 || fail +echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME 2> /dev/null && fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail + +# Key Slot 1 and key material section 1 must change, the rest must not +prepare "[9] add key test for key files" +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV $KEY1 || fail +$CRYPTSETUP -d $KEY1 luksOpen $LOOPDEV $DEV_NAME || fail + +# Key Slot 1 and key material section 1 must change, the rest must not +prepare "[10] delete key test with key1 as remaining key" +$CRYPTSETUP -d $KEY1 luksKillSlot $LOOPDEV 0 || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail + +# Delete last slot +prepare "[11] delete last key" wipe +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $LOOPDEV $FAST_PBKDF_OPT || fail +echo $PWD1 | $CRYPTSETUP luksKillSlot $LOOPDEV 0 || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail + +# Format test for ESSIV, and some other parameters. +prepare "[12] parameter variation test" wipe +$CRYPTSETUP -q $FAST_PBKDF_OPT -c aes-cbc-essiv:sha256 -s 128 luksFormat --type luks2 $LOOPDEV $KEY1 || fail +$CRYPTSETUP -d $KEY1 luksOpen $LOOPDEV $DEV_NAME || fail + +prepare "[13] open/close - stacked devices" wipe +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 $LOOPDEV $FAST_PBKDF_OPT || fail +echo $PWD1 | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 /dev/mapper/$DEV_NAME $FAST_PBKDF_OPT || fail +echo $PWD1 | $CRYPTSETUP -q luksOpen /dev/mapper/$DEV_NAME $DEV_NAME2 || fail +$CRYPTSETUP -q luksClose $DEV_NAME2 || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail + +prepare "[14] format/open - passphrase on stdin & new line" wipe +# stdin defined by "-" must take even newline +#echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP -q luksFormat $LOOPDEV - || fail +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP $FAST_PBKDF_OPT -q --key-file=- luksFormat --type luks2 $LOOPDEV || fail +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP -q --key-file=- luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +# now also try --key-file +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP $FAST_PBKDF_OPT -q luksFormat --type luks2 $LOOPDEV --key-file=- || fail +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP -q --key-file=- luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail +# process newline if from stdin +echo -n -e "$PWD1\n$PWD2" | $CRYPTSETUP $FAST_PBKDF_OPT -q luksFormat --type luks2 $LOOPDEV || fail +echo "$PWD1" | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail + +prepare "[15] UUID - use and report provided UUID" wipe +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --uuid blah --type luks2 $LOOPDEV 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --uuid $TEST_UUID --type luks2 $LOOPDEV || fail +tst=$($CRYPTSETUP -q luksUUID $LOOPDEV) +[ "$tst"x = "$TEST_UUID"x ] || fail +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail +$CRYPTSETUP -q luksUUID --uuid $TEST_UUID $LOOPDEV || fail +tst=$($CRYPTSETUP -q luksUUID $LOOPDEV) +[ "$tst"x = "$TEST_UUID"x ] || fail + +prepare "[16] luksFormat" wipe +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --master-key-file /dev/urandom --type luks2 $LOOPDEV || fail +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --master-key-file /dev/urandom --type luks2 $LOOPDEV -d $KEY1 || fail +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --master-key-file /dev/urandom -s 256 --uuid $TEST_UUID --type luks2 $LOOPDEV $KEY1 || fail +$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail +# open by UUID +force_uevent # some systems do not update loop by-uuid +$CRYPTSETUP luksOpen -d $KEY1 UUID=X$TEST_UUID $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP luksOpen -d $KEY1 UUID=$TEST_UUID $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail +# empty keyfile +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEYE || fail +$CRYPTSETUP luksOpen -d $KEYE $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail +# open by volume key +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT -s 256 --master-key-file $KEY1 --type luks2 $LOOPDEV || fail +$CRYPTSETUP luksOpen --master-key-file /dev/urandom $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP luksOpen --master-key-file $KEY1 $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail + +prepare "[17] AddKey volume key, passphrase and keyfile" wipe +# masterkey +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --master-key-file /dev/zero --key-slot 3 || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "3: luks2" || fail +echo $PWD2 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV --master-key-file /dev/zero --key-slot 4 || fail +echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase --key-slot 4 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "4: luks2" || fail +echo $PWD3 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV --master-key-file /dev/null --key-slot 5 2>/dev/null && fail +$CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV --master-key-file /dev/zero --key-slot 5 $KEY1 || fail +$CRYPTSETUP luksOpen $LOOPDEV --test-passphrase --key-slot 5 -d $KEY1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" || fail + +# special "-" handling +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY1 --key-slot 3 || fail +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV -d $KEY1 - || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV -d - --test-passphrase || fail +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV -d - $KEY2 || fail +$CRYPTSETUP luksOpen $LOOPDEV -d $KEY2 --test-passphrase || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV -d - -d $KEY1 --test-passphrase 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV -d $KEY1 -d $KEY1 --test-passphrase 2>/dev/null && fail + +# [0]PWD1 [1]PWD2 [2]$KEY1/1 [3]$KEY1 [4]$KEY2 +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY1 --key-slot 3 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "3: luks2" || fail +$CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 $KEY2 --key-slot 3 2>/dev/null && fail +# keyfile/keyfile +$CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 $KEY2 --key-slot 4 || fail +$CRYPTSETUP luksOpen $LOOPDEV -d $KEY2 --test-passphrase --key-slot 4 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "4: luks2" || fail +# passphrase/keyfile +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV -d $KEY1 --key-slot 0 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "0: luks2" || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase --key-slot 0 || fail +# passphrase/passphrase +echo -e "$PWD1\n$PWD2\n" | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV --key-slot 1 || fail +echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase --key-slot 1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" || fail +# keyfile/passphrase +echo -e "$PWD2\n" | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV $KEY1 --key-slot 2 --new-keyfile-size 1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "2: luks2" || fail + +prepare "[18] RemoveKey passphrase and keyfile" reuse +$CRYPTSETUP luksDump $LOOPDEV | grep -q "3: luks2" || fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "3: luks2" && fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY1 2>/dev/null && fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 --keyfile-size 1 2>/dev/null && fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "4: luks2" || fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "4: luks2" && fail +# if password or keyfile is provided, batch mode must not suppress it +echo "badpw" | $CRYPTSETUP luksKillSlot $LOOPDEV 2 2>/dev/null && fail +echo "badpw" | $CRYPTSETUP luksKillSlot $LOOPDEV 2 -q 2>/dev/null && fail +echo "badpw" | $CRYPTSETUP luksKillSlot $LOOPDEV 2 --key-file=- 2>/dev/null && fail +echo "badpw" | $CRYPTSETUP luksKillSlot $LOOPDEV 2 --key-file=- -q 2>/dev/null && fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "2: luks2" || fail +# kill slot using passphrase from 1 +echo $PWD2 | $CRYPTSETUP luksKillSlot $LOOPDEV 2 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "2: luks2" && fail +# remove key0 / slot 0 +echo $PWD1 | $CRYPTSETUP luksRemoveKey $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "0: luks2" && fail +# last keyslot, in batch mode no passphrase needed... +$CRYPTSETUP luksKillSlot -q $LOOPDEV 1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" && fail + +prepare "[19] create & status & resize" wipe +echo $PWD1 | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash xxx 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --cipher aes-cbc-essiv:sha256 --offset 3 --skip 4 --readonly || fail +$CRYPTSETUP -q status $DEV_NAME | grep "offset:" | grep -q "3 sectors" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "skipped:" | grep -q "4 sectors" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "mode:" | grep -q "readonly" || fail +$CRYPTSETUP -q resize $DEV_NAME --size 100 || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP -q resize $DEV_NAME || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "19997 sectors" || fail +# Resize underlying loop device as well +truncate -s 16M $IMG || fail +$CRYPTSETUP -q resize $DEV_NAME || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "32765 sectors" || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +$CRYPTSETUP -q status $DEV_NAME >/dev/null && fail +echo $PWD1 | $CRYPTSETUP create $DEV_NAME --hash sha1 $LOOPDEV || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q create $DEV_NAME --hash sha1 $LOOPDEV || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q create $DEV_NAME --hash sha1 --size 100 $LOOPDEV || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +# verify is ignored on non-tty input +echo $PWD1 | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --verify-passphrase 2>/dev/null || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 --key-size 255 2>/dev/null && fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 --key-size -1 2>/dev/null && fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 -l -1 2>/dev/null && fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 || fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 2>/dev/null && fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d blah 2>/dev/null && fail +$CRYPTSETUP -q remove $DEV_NAME || fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d /dev/urandom || fail +$CRYPTSETUP -q remove $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail +if dm_crypt_keyring_support; then + echo | $CRYPTSETUP -q resize --size 100 $DEV_NAME 2>/dev/null && fail +fi +echo $PWD1 | $CRYPTSETUP -q resize --size 100 $DEV_NAME || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP close $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksOpen --disable-keyring $LOOPDEV $DEV_NAME || fail +echo | $CRYPTSETUP -q resize --size 100 $DEV_NAME || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP close $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail +if dm_crypt_keyring_support; then + $CRYPTSETUP -q resize --disable-keyring --size 100 $DEV_NAME 2>/dev/null && fail +fi + +prepare "[20] Disallow open/create if already mapped." wipe +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 || fail +$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 2>/dev/null && fail +$CRYPTSETUP create $DEV_NAME2 $LOOPDEV -d $KEY1 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV 2>/dev/null && fail +$CRYPTSETUP remove $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME2 2>/dev/null && fail +$CRYPTSETUP luksClose $DEV_NAME || fail + +prepare "[21] luksDump" wipe +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --uuid $TEST_UUID --type luks2 $LOOPDEV $KEY1 || fail +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT $LOOPDEV -d $KEY1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "0: luks2" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q $TEST_UUID || fail +echo $PWDW | $CRYPTSETUP luksDump $LOOPDEV --dump-master-key 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP luksDump $LOOPDEV --dump-master-key | grep -q "MK dump:" || can_fail_fips +$CRYPTSETUP luksDump -q $LOOPDEV --dump-master-key -d $KEY1 | grep -q "MK dump:" || can_fail_fips + +prepare "[22] remove disappeared device" wipe +dmsetup create $DEV_NAME --table "0 10000 linear $LOOPDEV 2" || fail +echo $PWD1 | $CRYPTSETUP -q $FAST_PBKDF_OPT luksFormat --type luks2 /dev/mapper/$DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q luksOpen /dev/mapper/$DEV_NAME $DEV_NAME2 || fail +# underlying device now returns error but node is still present +dmsetup load $DEV_NAME --table "0 10000 error" || fail +dmsetup resume $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME2 || fail +dmsetup remove $DEV_NAME || fail + +prepare "[23] ChangeKey passphrase and keyfile" wipe +# [0]$KEY1 [1]key0 +$CRYPTSETUP -q luksFormat --type luks2 $LOOPDEV $KEY1 $FAST_PBKDF_OPT --key-slot 0 || fail +echo $PWD1 | $CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 --key-slot 1 || fail +# keyfile [0] / keyfile [0] +$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 $KEY2 --key-slot 0 || fail +# passphrase [1] / passphrase [1] +echo -e "$PWD1\n$PWD2\n" | $CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT --key-slot 1 || fail +# keyfile [0] / keyfile [new] +$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY2 $KEY1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "0: luks2" && fail +# passphrase [1] / passphrase [new] +echo -e "$PWD2\n$PWD1\n" | $CRYPTSETUP luksChangeKey $FAST_PBKDF_OPT $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" && fail +# use all slots +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT || fail +# still allows replace +#FIXME +#$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 $KEY2 || fail +#$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 $KEY2 2>/dev/null && fail + +prepare "[24] Keyfile limit" wipe +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY1 --key-slot 0 -l 13 || fail +$CRYPTSETUP --key-file=$KEY1 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 0 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l -1 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 14 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 13 --keyfile-offset 1 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 13 --keyfile-offset -1 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 13 luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksClose $DEV_NAME || fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 2>/dev/null && fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 -l 14 2>/dev/null && fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 -l -1 2>/dev/null && fail +$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT -l 13 --new-keyfile-size 12 || fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 2>/dev/null && fail +$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 -l 12 || fail +$CRYPTSETUP luksChangeKey $LOOPDEV -d $KEY1 $KEY2 2>/dev/null && fail +$CRYPTSETUP luksChangeKey $LOOPDEV -d $KEY1 $KEY2 -l 14 2>/dev/null && fail +$CRYPTSETUP luksChangeKey $LOOPDEV -d $KEY1 $KEY2 $FAST_PBKDF_OPT -l 13 || fail +# -l is ignored for stdin if _only_ passphrase is used +echo $PWD1 | $CRYPTSETUP luksAddKey $LOOPDEV -d $KEY2 $FAST_PBKDF_OPT || fail +# this is stupid, but expected +echo $PWD1 | $CRYPTSETUP luksRemoveKey $LOOPDEV -l 11 2>/dev/null && fail +echo $PWDW"0" | $CRYPTSETUP luksRemoveKey $LOOPDEV -l 12 2>/dev/null && fail +echo -e "$PWD1\n" | $CRYPTSETUP luksRemoveKey $LOOPDEV -d- -l 12 || fail +# offset +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY1 --key-slot 0 -l 13 --keyfile-offset 16 || fail +$CRYPTSETUP --key-file=$KEY1 -l 13 --keyfile-offset 15 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY1 -l 13 --keyfile-offset 16 luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksClose $DEV_NAME || fail +$CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY1 -l 13 --keyfile-offset 16 $KEY2 --new-keyfile-offset 1 || fail +$CRYPTSETUP --key-file=$KEY2 --keyfile-offset 11 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=$KEY2 --keyfile-offset 1 luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksClose $DEV_NAME || fail +$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY2 --keyfile-offset 1 $KEY2 --new-keyfile-offset 0 || fail +$CRYPTSETUP luksOpen -d $KEY2 $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksClose $DEV_NAME || fail + +prepare "[25] Create shared segments" wipe +echo $PWD1 | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --offset 0 --size 256 || fail +echo $PWD1 | $CRYPTSETUP create $DEV_NAME2 $LOOPDEV --hash sha1 --offset 512 --size 256 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP create $DEV_NAME2 $LOOPDEV --hash sha1 --offset 512 --size 256 --shared || fail +$CRYPTSETUP -q remove $DEV_NAME2 || fail +$CRYPTSETUP -q remove $DEV_NAME || fail + +prepare "[26] Suspend/Resume" wipe +# only LUKS is supported +echo $PWD1 | $CRYPTSETUP create $DEV_NAME --hash sha1 $LOOPDEV || fail +$CRYPTSETUP luksSuspend $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP luksResume $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP -q remove $DEV_NAME || fail +$CRYPTSETUP luksSuspend $DEV_NAME 2>/dev/null && fail +# LUKS +echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail +echo $PWD1 | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksSuspend $DEV_NAME || fail +$CRYPTSETUP -q resize $DEV_NAME 2>/dev/null && fail +echo $PWDW | $CRYPTSETUP luksResume $DEV_NAME -T 1 2>/dev/null && fail +echo $PWD1 | $CRYPTSETUP luksResume $DEV_NAME || fail +$CRYPTSETUP -q luksClose $DEV_NAME || fail + +prepare "[27] luksOpen with specified key slot number" new +# first, let's try passphrase option +echo $PWD3 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT -S 5 --type luks2 $LOOPDEV || fail +echo $PWD3 | $CRYPTSETUP luksOpen -S 4 $LOOPDEV $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +echo $PWD3 | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME || fail +check_exists +$CRYPTSETUP luksClose $DEV_NAME || fail +echo -e "$PWD3\n$PWD1" | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 0 $LOOPDEV || fail +echo $PWD3 | $CRYPTSETUP luksOpen -S 0 $LOOPDEV $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +echo $PWD1 | $CRYPTSETUP luksOpen -S 5 $LOOPDEV $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +# second, try it with keyfiles +$CRYPTSETUP luksFormat -q -S 5 $FAST_PBKDF_OPT -d $KEY5 --type luks2 $LOOPDEV || fail +$CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 1 -d $KEY5 $LOOPDEV $KEY1 || fail +$CRYPTSETUP luksOpen -S 5 -d $KEY5 $LOOPDEV $DEV_NAME || fail +check_exists +$CRYPTSETUP luksClose $DEV_NAME || fail +$CRYPTSETUP luksOpen -S 1 -d $KEY5 $LOOPDEV $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +$CRYPTSETUP luksOpen -S 5 -d $KEY1 $LOOPDEV $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +# test keyslot not assigned to segment is unable to unlock volume +# otoh it should be allowed to test for proper passphrase +echo $PWD1 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU || fail +echo $PWD1 | $CRYPTSETUP open --test-passphrase $HEADER_KEYU || fail +echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +echo $PWD1 | $CRYPTSETUP open $HEADER_KEYU $DEV_NAME && fail +[ -b /dev/mapper/$DEV_NAME ] && fail +echo $PWD0 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU $DEV_NAME && fail +$CRYPTSETUP luksKillSlot -q $HEADER_KEYU 0 +$CRYPTSETUP luksDump $HEADER_KEYU | grep -q "0: luks2" && fail +echo $PWD1 | $CRYPTSETUP open -S1 --test-passphrase $HEADER_KEYU || fail +echo $PWD1 | $CRYPTSETUP open --test-passphrase $HEADER_KEYU || fail +echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME && fail + +prepare "[28] Detached LUKS header" wipe +dd if=/dev/zero of=$HEADER_IMG bs=1M count=4 >/dev/null 2>&1 +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG || fail +#FIXME +#echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --align-payload 1 >/dev/null 2>&1 && fail +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 8192 || fail +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG --align-payload 0 || fail +echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP -q resize $DEV_NAME --size 100 --header $HEADER_IMG || fail +$CRYPTSETUP -q status $DEV_NAME --header $HEADER_IMG | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "type:" | grep -q "n/a" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP luksSuspend $DEV_NAME --header $HEADER_IMG || fail +echo $PWD1 | $CRYPTSETUP luksResume $DEV_NAME --header $HEADER_IMG || fail +$CRYPTSETUP luksClose $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 5 _fakedev_ --header $HEADER_IMG $KEY5 || fail +$CRYPTSETUP luksDump _fakedev_ --header $HEADER_IMG | grep -q "5: luks2" || fail +$CRYPTSETUP luksKillSlot -q _fakedev_ --header $HEADER_IMG 5 || fail +$CRYPTSETUP luksDump _fakedev_ --header $HEADER_IMG | grep -q "5: luks2" && fail + +#prepare "[29] Repair metadata" wipe +#FIXME +#$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT $LOOPDEV $KEY1 --key-slot 0 || fail +# second sector overwrite should corrupt keyslot 6+7 +#dd if=/dev/urandom of=$LOOPDEV bs=512 seek=1 count=1 >/dev/null 2>&1 +#$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME >/dev/null 2>&1 && fail +#$CRYPTSETUP -q repair $LOOPDEV >/dev/null 2>&1 || fail +#$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail +#$CRYPTSETUP luksClose $DEV_NAME || fail + +prepare "[30] LUKS erase" wipe +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV $KEY5 --key-slot 5 || fail +$CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 1 -d $KEY5 $LOOPDEV $KEY1 || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" || fail +$CRYPTSETUP luksErase -q $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" && fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" && fail + +prepare "[31] LUKS convert" wipe +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks1 $LOOPDEV $KEY5 --key-slot 5 || fail +$CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 1 -d $KEY5 $LOOPDEV $KEY1 || fail +$CRYPTSETUP -q convert --type luks1 $LOOPDEV >/dev/null 2>&1 && fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 1: ENABLED" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 5: ENABLED" || fail +$CRYPTSETUP -q convert --type luks2 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "1: luks2" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" || fail +$CRYPTSETUP -q convert --type luks1 $LOOPDEV || fail + +# FIXME: perhaps better to test in keyring-test script +if dm_crypt_keyring_support; then + prepare "[32] LUKS2 key in keyring" wipe + dd if=/dev/zero of=$HEADER_IMG bs=1M count=4 >/dev/null 2>&1 + which sha1sum > /dev/null 2>&1 || skip "sha1sum is missing" + echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG || fail + # check keyring support detection works as expected + rmmod dm-crypt > /dev/null 2>&1 || true + echo $PWD1 | $CRYPTSETUP open $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail + $CRYPTSETUP -q status $DEV_NAME | grep "key location:" | grep -q "keyring" || fail + dd if=/dev/urandom of=/dev/mapper/$DEV_NAME bs=4k count=2500 oflag=direct > /dev/null 2>&1 || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_KEYRING + $CRYPTSETUP close $DEV_NAME || fail + echo $PWD1 | $CRYPTSETUP open $LOOPDEV --disable-keyring --header $HEADER_IMG $DEV_NAME || fail + $CRYPTSETUP -q status $DEV_NAME | grep "key location:" | grep -q "dm-crypt" || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_DMCRYPT + diff $CHKS_DMCRYPT $CHKS_KEYRING || fail + $CRYPTSETUP close $DEV_NAME || fail + + echo $PWD1 | $CRYPTSETUP open $LOOPDEV --disable-keyring --header $HEADER_IMG $DEV_NAME || fail + dd if=/dev/urandom of=/dev/mapper/$DEV_NAME bs=4k count=2500 oflag=direct > /dev/null 2>&1 || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_DMCRYPT + $CRYPTSETUP luksSuspend $DEV_NAME || fail + echo $PWD1 | $CRYPTSETUP luksResume $DEV_NAME --header $HEADER_IMG || fail + $CRYPTSETUP -q status $DEV_NAME | grep "key location:" | grep -q "keyring" || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_KEYRING + diff $CHKS_DMCRYPT $CHKS_KEYRING || fail + $CRYPTSETUP close $DEV_NAME || fail + + echo $PWD1 | $CRYPTSETUP open $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail + dd if=/dev/urandom of=/dev/mapper/$DEV_NAME bs=4k count=2500 oflag=direct > /dev/null 2>&1 || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_KEYRING + $CRYPTSETUP luksSuspend $DEV_NAME || fail + echo $PWD1 | $CRYPTSETUP luksResume --disable-keyring $DEV_NAME --header $HEADER_IMG || fail + $CRYPTSETUP -q status $DEV_NAME | grep "key location:" | grep -q "dm-crypt" || fail + sha1sum /dev/mapper/$DEV_NAME > $CHKS_DMCRYPT + diff $CHKS_DMCRYPT $CHKS_KEYRING || fail + $CRYPTSETUP close $DEV_NAME || fail +fi + +# FIXME: candidate for non-root tests +if [ $HAVE_KEYRING -gt 0 ]; then + prepare "[33] tokens" wipe + + test_and_prepare_keyring + + echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail + $CRYPTSETUP token add $LOOPDEV --key-description $TEST_TOKEN0 --token-id 3 || fail + $CRYPTSETUP luksDump $LOOPDEV | grep -q -e "3: luks2-keyring" || fail + # keyslot 5 is inactive + $CRYPTSETUP token add $LOOPDEV --key-description $TEST_TOKEN1 --key-slot 5 2> /dev/null && fail + # key description is not reachable + $CRYPTSETUP open --token-only $LOOPDEV --test-passphrase && fail + # wrong passphrase + load_key user $TEST_TOKEN0 "blabla" "$TEST_KEYRING" || fail "Cannot load 32 byte user key type" + $CRYPTSETUP open --token-only $LOOPDEV --test-passphrase && fail + load_key user $TEST_TOKEN0 $PWD1 "$TEST_KEYRING" || fail "Cannot load 32 byte user key type" + $CRYPTSETUP open --token-only $LOOPDEV --test-passphrase || fail + $CRYPTSETUP open --token-only $LOOPDEV $DEV_NAME || fail + $CRYPTSETUP status $DEV_NAME > /dev/null || fail + $CRYPTSETUP close $DEV_NAME || fail + $CRYPTSETUP token remove --token-id 3 $LOOPDEV || fail + $CRYPTSETUP luksDump $LOOPDEV | grep -q -e "3: luks2-keyring" && fail + + # test we can remove keyslot with token + echo -e "$PWD1\n$PWD2" | $CRYPTSETUP luksAddKey -S4 $FAST_PBKDF_OPT $LOOPDEV || fail + $CRYPTSETUP token add $LOOPDEV --key-description $TEST_TOKEN1 --key-slot 4 || fail + $CRYPTSETUP -q luksKillSlot $LOOPDEV 4 || fail +fi + +prepare "[34] LUKS keyslot priority" wipe +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV -S 1 || fail +echo -e "$PWD1\n$PWD2" | $CRYPTSETUP luksAddKey $LOOPDEV $FAST_PBKDF_OPT -S 5 || fail +$CRYPTSETUP config $LOOPDEV -S 0 --priority prefer && fail +$CRYPTSETUP config $LOOPDEV -S 1 --priority bla >/dev/null 2>&1 && fail +$CRYPTSETUP config $LOOPDEV -S 1 --priority ignore || fail +echo $PWD1 | $CRYPTSETUP open $LOOPDEV --test-passphrase && fail +echo $PWD1 | $CRYPTSETUP open $LOOPDEV --test-passphrase -S 1 || fail +echo $PWD2 | $CRYPTSETUP open $LOOPDEV --test-passphrase || fail +$CRYPTSETUP config $LOOPDEV -S 1 --priority normal || fail +echo $PWD1 | $CRYPTSETUP open $LOOPDEV --test-passphrase || fail +$CRYPTSETUP config $LOOPDEV -S 1 --priority ignore || fail +echo $PWD1 | $CRYPTSETUP open $LOOPDEV --test-passphrase && fail + +prepare "[35] LUKS label and subsystem" wipe +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "(no subsystem)" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "(no label)" || fail +echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --subsystem SatelliteTwo --label TheLabel || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "SatelliteTwo" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "TheLabel" || fail +$CRYPTSETUP config $LOOPDEV --subsystem SatelliteThree +$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "SatelliteThree" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "(no label)" || fail +$CRYPTSETUP config $LOOPDEV --subsystem SatelliteThree --label TheLabel +$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "SatelliteThree" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "TheLabel" || fail + +prepare "[36] LUKS PBKDF setting" wipe +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf bla $LOOPDEV >/dev/null 2>&1 && fail +# Force setting, no benchmark. PBKDF2 has 1000 iterations as a minimum +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf pbkdf2 --pbkdf-force-iterations 999 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Iterations:" | grep -q "1000" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "PBKDF:" | grep -q "pbkdf2" || fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf pbkdf2 --pbkdf-force-iterations 1234 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Iterations:" | grep -q "1234" || fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf argon2id --pbkdf-force-iterations 1 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "PBKDF:" | grep -q "argon2id" || fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf argon2i --pbkdf-force-iterations 1 \ + --pbkdf-memory 1234 --pbkdf-parallel 1 $LOOPDEV || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "PBKDF:" | grep -q "argon2i" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Time:" | grep -q "1" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Memory:" | grep -q "1234" || fail +$CRYPTSETUP luksDump $LOOPDEV | grep "Threads:" | grep -q "1" || fail +# Benchmark +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf argon2i -i 500 --pbkdf-memory 1234 --pbkdf-parallel 1 $LOOPDEV || fail +[ 0"$($CRYPTSETUP luksDump $LOOPDEV | grep "Time:" | cut -d: -f 2 | sed -e 's/\ //g')" -gt 0 ] || fail +[ 0"$($CRYPTSETUP luksDump $LOOPDEV | grep "Memory:" | cut -d: -f 2 | sed -e 's/\ //g')" -gt 0 ] || fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf pbkdf2 -i 500 $LOOPDEV || fail +[ 0"$($CRYPTSETUP luksDump $LOOPDEV | grep -m1 "Iterations:" | cut -d' ' -f 2 | sed -e 's/\ //g')" -gt 1000 ] || fail + +remove_mapping +exit 0 diff --git a/tests/compatimage2.img.xz b/tests/compatimage2.img.xz new file mode 100644 index 00000000..ceaeafce Binary files /dev/null and b/tests/compatimage2.img.xz differ diff --git a/tests/conversion_imgs.tar.xz b/tests/conversion_imgs.tar.xz new file mode 100644 index 00000000..fa3985d8 Binary files /dev/null and b/tests/conversion_imgs.tar.xz differ diff --git a/tests/device-test b/tests/device-test index 4ce906d4..6219177d 100755 --- a/tests/device-test +++ b/tests/device-test @@ -5,6 +5,7 @@ MNT_DIR="./mnt_luks" DEV_NAME="dummy" PWD1="93R4P4pIqAH8" PWD2="mymJeD8ivEhE" +FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" cleanup() { [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME @@ -30,11 +31,11 @@ skip() exit 77 } -format() # key_bits expected [forced] +format() # format { dd if=/dev/zero of=$DEV bs=1M count=5 >/dev/null 2>&1 - echo $PWD1 | $CRYPTSETUP luksFormat $DEV -q -i1 -c aes-cbc-essiv:sha256 + echo $PWD1 | $CRYPTSETUP luksFormat --type $1 $DEV -q $FAST_PBKDF_OPT -c aes-cbc-essiv:sha256 [ $? -ne 0 ] && fail "Format failed." # test some operation, just in case @@ -55,7 +56,7 @@ fi echo "[1] Using tmpfs for image" DEV="$MNT_DIR/test.img" mount -t tmpfs none $MNT_DIR || skip "Mounting tmpfs not available." -format +format luks1 echo "[2] Kernel dmcrypt performace options" echo -e "$PWD1" | $CRYPTSETUP open --type plain $DEV $DEV_NAME --perf-same_cpu_crypt >/dev/null 2>&1 @@ -81,6 +82,25 @@ else $CRYPTSETUP status $DEV_NAME | grep -q same_cpu_crypt || fail $CRYPTSETUP status $DEV_NAME | grep -q discards || fail $CRYPTSETUP close $DEV_NAME || fail + + format luks2 + echo -e "$PWD1" | $CRYPTSETUP open $DEV $DEV_NAME --perf-same_cpu_crypt --perf-submit_from_crypt_cpus --persistent || fail + $CRYPTSETUP status $DEV_NAME | grep -q same_cpu_crypt || fail + $CRYPTSETUP status $DEV_NAME | grep -q submit_from_crypt_cpus || fail + $CRYPTSETUP close $DEV_NAME || fail + # Stored in metadata + echo -e "$PWD1" | $CRYPTSETUP open $DEV $DEV_NAME || fail + $CRYPTSETUP status $DEV_NAME | grep -q same_cpu_crypt || fail + $CRYPTSETUP status $DEV_NAME | grep -q submit_from_crypt_cpus || fail + $CRYPTSETUP close $DEV_NAME || fail + echo -e "$PWD1" | $CRYPTSETUP open $DEV $DEV_NAME --perf-same_cpu_crypt --allow-discards --persistent || fail + $CRYPTSETUP status $DEV_NAME | grep -q same_cpu_crypt || fail + $CRYPTSETUP status $DEV_NAME | grep -q discards || fail + $CRYPTSETUP close $DEV_NAME || fail + echo -e "$PWD1" | $CRYPTSETUP open $DEV $DEV_NAME || fail + $CRYPTSETUP status $DEV_NAME | grep -q same_cpu_crypt || fail + $CRYPTSETUP status $DEV_NAME | grep -q discards || fail + $CRYPTSETUP close $DEV_NAME || fail fi cleanup diff --git a/tests/generators/generate-luks2-area-in-json-hdr-space-json0.img.sh b/tests/generators/generate-luks2-area-in-json-hdr-space-json0.img.sh new file mode 100755 index 00000000..3938f7be --- /dev/null +++ b/tests/generators/generate-luks2-area-in-json-hdr-space-json0.img.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with one area accessing luks +# header space +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + # make area 7 access the luks2 header space + OFFS=$((2*LUKS2_HDR_SIZE*512-1)) + LEN=1 + json_str=$(jq -c --arg off $OFFS --arg len $LEN \ + '.keyslots."0".area.offset = $off | .keyslots."0".area.size = $len' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c --arg off $OFFS --arg len $LEN \ + 'if (.keyslots."0".area.offset != $off) or (.keyslots."0".area.size != $len) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-correct-full-json0.img.sh b/tests/generators/generate-luks2-correct-full-json0.img.sh new file mode 100755 index 00000000..f32f84bc --- /dev/null +++ b/tests/generators/generate-luks2-correct-full-json0.img.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with correct json of maximal size in primary slot. +# Secondary header is broken on purpose. +# + +# $1 full target dir +# $2 full source luks2 image + +PATTERN="\"config\":{" +KEY="\"config_key\":\"" + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_len=${#json_str} + pindex=$(strindex $json_str $PATTERN) + test $pindex -gt 0 || exit 2 + + offset=${#PATTERN} + offset=$((offset+pindex)) + key_len=${#KEY} + remain=$((LUKS2_JSON_SIZE*512-json_len-key_len-2)) # -2: closing '"' and terminating '\0' + if [ ${json_str:offset:1} = "}" ]; then + format_str="%s%s%s" + else + format_str="%s%s,%s" + remain=$((remain-1)) # also count with separating ',' + fi + test $remain -gt 0 || exit 2 + + fill=$(repeat_str "X" $remain)"\"" + + printf $format_str $KEY $fill ${json_str:$offset} | _dd of=$TMPDIR/json0 bs=1 seek=$offset conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + #json_str_res0=$(< $TMPDIR/json_res0) + read -r json_str_res0 < $TMPDIR/json_res0 + test ${#json_str_res0} -eq $((LUKS2_JSON_SIZE*512-1)) || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-corrupted-hdr0-with-correct-chks.img.sh b/tests/generators/generate-luks2-corrupted-hdr0-with-correct-chks.img.sh new file mode 100755 index 00000000..3d4f7296 --- /dev/null +++ b/tests/generators/generate-luks2-corrupted-hdr0-with-correct-chks.img.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with malformed json but correct checksum in primary header +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_len=${#json_str} + json_len=$((json_len-1)) # to replace json closing '}' + json_new_str="${json_str:0:json_len},\"" + + while [ ${#json_new_str} -le $((LUKS2_JSON_SIZE*512)) ]; do + json_new_str=$json_new_str"all_work_and_no_play_makes_Jack_a_dull_boy_" + done + + printf "%s" $json_new_str | _dd of=$TMPDIR/json0 bs=512 count=$LUKS2_JSON_SIZE + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG +} + +function check() +{ + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + read -r json_str_res0 < $TMPDIR/json_res0 + test ${#json_str_res0} -eq $((LUKS2_JSON_SIZE*512)) || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-corrupted-hdr1-with-correct-chks.img.sh b/tests/generators/generate-luks2-corrupted-hdr1-with-correct-chks.img.sh new file mode 100755 index 00000000..026393c3 --- /dev/null +++ b/tests/generators/generate-luks2-corrupted-hdr1-with-correct-chks.img.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with malformed json but correct checksum in secondary header +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json1 $TGT_IMG $TMPDIR/json1 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json1 + json_len=${#json_str} + json_len=$((json_len-1)) # to replace json closing '}' + json_new_str="${json_str:0:json_len},\"" + + while [ ${#json_new_str} -le $((LUKS2_JSON_SIZE*512)) ]; do + json_new_str=$json_new_str"all_work_and_no_play_makes_Jack_a_dull_boy_" + done + + printf "%s" $json_new_str | _dd of=$TMPDIR/json1 bs=512 count=$LUKS2_JSON_SIZE + + merge_bin_hdr_with_json $TMPDIR/hdr1 $TMPDIR/json1 $TMPDIR/area1 + erase_checksum $TMPDIR/area1 + chks1=$(calc_sha256_checksum_file $TMPDIR/area1) + write_checksum $chks1 $TMPDIR/area1 + write_luks2_hdr1 $TMPDIR/area1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + chks_res1=$(read_sha256_checksum $TMPDIR/hdr_res1) + test "$chks1" = "$chks_res1" || exit 2 + read_luks2_json1 $TGT_IMG $TMPDIR/json_res1 + read -r json_str_res1 < $TMPDIR/json_res1 + test ${#json_str_res1} -eq $((LUKS2_JSON_SIZE*512)) || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-checksum-both-hdrs.img.sh b/tests/generators/generate-luks2-invalid-checksum-both-hdrs.img.sh new file mode 100755 index 00000000..be98722a --- /dev/null +++ b/tests/generators/generate-luks2-invalid-checksum-both-hdrs.img.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with bad checksum in both binary headerer +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + chks0=$(echo "Arbitrary chosen string: D'oh!" | calc_sha256_checksum_stdin) + chks1=$(echo "D'oh!: arbitrary chosen string" | calc_sha256_checksum_stdin) + write_checksum $chks0 $TGT_IMG + write_checksum $chks1 $TMPDIR/hdr1 + write_luks2_bin_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + chks_res0=$(read_sha256_checksum $TGT_IMG) + chks_res1=$(read_sha256_checksum $TMPDIR/hdr1) + test "$chks0" = "$chks_res0" || exit 2 + test "$chks1" = "$chks_res1" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-checksum-hdr0.img.sh b/tests/generators/generate-luks2-invalid-checksum-hdr0.img.sh new file mode 100755 index 00000000..ac75ccb6 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-checksum-hdr0.img.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with bad checksum in primary binary header +# + +# 1 full target dir +# 2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG +} + +function generate() +{ + chks=$(echo "Arbitrary chosen string: D'oh!" | calc_sha256_checksum_stdin) + write_checksum $chks $TGT_IMG +} + +function check() +{ + chks_res=$(read_sha256_checksum $TGT_IMG) + test "$chks" = "$chks_res" || exit 2 +} + +#function cleanup() +#{ +#} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +#cleanup diff --git a/tests/generators/generate-luks2-invalid-checksum-hdr1.img.sh b/tests/generators/generate-luks2-invalid-checksum-hdr1.img.sh new file mode 100755 index 00000000..f0ca01ae --- /dev/null +++ b/tests/generators/generate-luks2-invalid-checksum-hdr1.img.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate header with bad checksum in secondary binary header +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + chks=$(echo "Arbitrary chosen string: D'oh!" | calc_sha256_checksum_stdin) + write_checksum $chks $TMPDIR/hdr1 + write_luks2_bin_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + chks_res=$(read_sha256_checksum $TMPDIR/hdr1) + test "$chks" = "$chks_res" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-json-size-c0.img.sh b/tests/generators/generate-luks2-invalid-json-size-c0.img.sh new file mode 100755 index 00000000..2866b0b0 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-json-size-c0.img.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with invalid json_size in config section +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + JS=$(((LUKS2_HDR_SIZE-LUKS2_BIN_HDR_SIZE)*512+4096)) + json_str=$(jq -c --arg js $JS '.config.json_size = ($js | tostring)' $TMPDIR/json0) + test -n "$json_str" || exit 2 + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c --arg js $JS 'if .config.json_size != ($js | tostring ) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-json-size-c1.img.sh b/tests/generators/generate-luks2-invalid-json-size-c1.img.sh new file mode 100755 index 00000000..dcab9bc3 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-json-size-c1.img.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with invalid json_size in config section +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + JS=$(((LUKS2_HDR_SIZE-LUKS2_BIN_HDR_SIZE)*512-4096)) + json_str=$(jq -c --arg js $JS '.config.json_size = ($js | tostring)' $TMPDIR/json0) + test -n "$json_str" || exit 2 + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c --arg js $JS 'if .config.json_size != ($js | tostring ) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-keyslots-size-c0.img.sh b/tests/generators/generate-luks2-invalid-keyslots-size-c0.img.sh new file mode 100755 index 00000000..c4f002f1 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-keyslots-size-c0.img.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with too large keyslots_size set in config section +# (iow config.keyslots_size = data_offset - keyslots_offset + 512) +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + # make area 7 being included in area 6 + OFFS=$((2*LUKS2_HDR_SIZE*512)) + json_str=$(jq -c --arg off $OFFS '.config.keyslots_size = (.segments."0".offset | tonumber - ($off | tonumber) + 4096 | tostring)' $TMPDIR/json0) + test -n "$json_str" || exit 2 + # [.keyslots[].area.offset | tonumber] | max | tostring ---> max offset in keyslot areas + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c --arg off $OFFS 'if .config.keyslots_size != ( .segments."0".offset | tonumber - ($off | tonumber) + 4096 | tostring ) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-keyslots-size-c1.img.sh b/tests/generators/generate-luks2-invalid-keyslots-size-c1.img.sh new file mode 100755 index 00000000..eff2064a --- /dev/null +++ b/tests/generators/generate-luks2-invalid-keyslots-size-c1.img.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with unaligned keyslots_size config section +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + json_str=$(jq -c '.config.keyslots_size = (.config.keyslots_size | tonumber - 1 | tostring)' $TMPDIR/json0) + test -n "$json_str" || exit 2 + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c 'if (.config.keyslots_size | tonumber % 4096) == 0 + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-keyslots-size-c2.img.sh b/tests/generators/generate-luks2-invalid-keyslots-size-c2.img.sh new file mode 100755 index 00000000..f70f39f8 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-keyslots-size-c2.img.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with keyslots_size less than sum of all keyslots area +# in json +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + json_str=$(jq '.config.keyslots_size = ([.keyslots[].area.size] | map(tonumber) | add - 4096 | tostring )' $TMPDIR/json0) + test -n "$json_str" || exit 2 + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c 'if .config.keyslots_size != ([.keyslots[].area.size ] | map(tonumber) | add - 4096 | tostring) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-object-type-json0.img.sh b/tests/generators/generate-luks2-invalid-object-type-json0.img.sh new file mode 100755 index 00000000..10638649 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-object-type-json0.img.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with well-formed json format +# where top level value is not of type object. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_str="[$json_str]" # make top level value an array + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + printf "%s" "$json_str" | _dd of=$TMPDIR/json0 bs=1 conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + read -r json_str_res0 < $TMPDIR/json_res0 + test "$json_str" = "$json_str_res0" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-invalid-opening-char-json0.img.sh b/tests/generators/generate-luks2-invalid-opening-char-json0.img.sh new file mode 100755 index 00000000..996d9975 --- /dev/null +++ b/tests/generators/generate-luks2-invalid-opening-char-json0.img.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with well-formed json prefixed +# with useless whitespace. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_str=" $json_str" # add useless opening whitespace + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + printf "%s" "$json_str" | _dd of=$TMPDIR/json0 bs=1 conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + IFS= read -r json_str_res0 < $TMPDIR/json_res0 + test "$json_str" = "$json_str_res0" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-missing-keyslot-referenced-in-digest.img.sh b/tests/generators/generate-luks2-missing-keyslot-referenced-in-digest.img.sh new file mode 100755 index 00000000..d6ebe3d6 --- /dev/null +++ b/tests/generators/generate-luks2-missing-keyslot-referenced-in-digest.img.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with missing keyslot object referenced +# in digest object +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str_orig < $TMPDIR/json0 + arr_len=$(jq -c -M '.digests."0".keyslots | length' $TMPDIR/json0) + # add missing keyslot reference in keyslots array of digest '0' + json_str=$(jq -r -c -M 'def arr: ["digests", "0", "keyslots"]; + def missks: getpath(["keyslots"]) | keys | max | tonumber + 1 | tostring; + setpath(arr; getpath(arr) + [ missks ])' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + new_arr_len=$(jq -c -M '.digests."0".keyslots | length' $TMPDIR/json_res0) + test $((arr_len+1)) -eq $new_arr_len || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-missing-keyslot-referenced-in-token.img.sh b/tests/generators/generate-luks2-missing-keyslot-referenced-in-token.img.sh new file mode 100755 index 00000000..85798e5a --- /dev/null +++ b/tests/generators/generate-luks2-missing-keyslot-referenced-in-token.img.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with missing keyslot object referenced +# in token object +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str_orig < $TMPDIR/json0 + # add missing keyslot reference in keyslots array of token '0' + json_str=$(jq -r -c -M 'def missks: getpath(["keyslots"]) | keys | max | tonumber + 1 | tostring; + .tokens += {"0":{"type":"dummy","keyslots":[ "0", missks ]}}' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + new_arr_len=$(jq -c -M '.tokens."0".keyslots | length' $TMPDIR/json_res0) + test $new_arr_len -eq 2 || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-missing-segment-referenced-in-digest.img.sh b/tests/generators/generate-luks2-missing-segment-referenced-in-digest.img.sh new file mode 100755 index 00000000..333462b3 --- /dev/null +++ b/tests/generators/generate-luks2-missing-segment-referenced-in-digest.img.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with missing segment object referenced +# in digest object +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str_orig < $TMPDIR/json0 + arr_len=$(jq -c -M '.digests."0".segments | length' $TMPDIR/json0) + # add missing keyslot reference in keyslots array of digest '0' + json_str=$(jq -c 'def arr: ["digests", "0", "segments"]; + def missseg: getpath(["segments"]) | keys | max | tonumber + 1 | tostring; + setpath(arr; getpath(arr) + [ missseg ])' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + new_arr_len=$(jq -c -M '.digests."0".segments | length' $TMPDIR/json_res0) + test $((arr_len+1)) -eq $new_arr_len || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-missing-trailing-null-byte-json0.img.sh b/tests/generators/generate-luks2-missing-trailing-null-byte-json0.img.sh new file mode 100755 index 00000000..916cff70 --- /dev/null +++ b/tests/generators/generate-luks2-missing-trailing-null-byte-json0.img.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with well-formed json but missing +# trailing null byte. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +PATTERN="\"config\":{" +KEY="\"config_key\":\"" + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_len=${#json_str} + pindex=$(strindex $json_str $PATTERN) + test $pindex -gt 0 || exit 2 + + offset=${#PATTERN} + offset=$((offset+pindex)) + key_len=${#KEY} + remain=$((LUKS2_JSON_SIZE*512-key_len-json_len-1)) # -1: closing '"' + if [ ${json_str:offset:1} = "}" ]; then + format_str="%s%s%s" + else + format_str="%s%s,%s" + remain=$((remain-1)) # also count with separating ',' + fi + test $remain -gt 0 || exit 2 + + fill=$(repeat_str "X" $remain) + fill=$(repeat_str "X" $remain)"\"" + + printf $format_str $KEY $fill ${json_str:$offset} | _dd of=$TMPDIR/json0 bs=1 seek=$offset conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + read -r json_str_res0 < $TMPDIR/json_res0 + test ${#json_str_res0} -eq $((LUKS2_JSON_SIZE*512)) || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-non-null-byte-beyond-json0.img.sh b/tests/generators/generate-luks2-non-null-byte-beyond-json0.img.sh new file mode 100755 index 00000000..0b5c27f8 --- /dev/null +++ b/tests/generators/generate-luks2-non-null-byte-beyond-json0.img.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with json area concluded with illegal +# byte beyond terminating '}' charcter. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_str="$json_str"X # add illegal 'X' beyond json format + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + printf '%s' $json_str | _dd of=$TMPDIR/json0 bs=1 conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + read -r json_str_res0 < $TMPDIR/json_res0 + local len=${#json_str_res0} + len=$((len-1)) + test ${json_str_res0:len:1} = "X" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-non-null-bytes-beyond-json0.img.sh b/tests/generators/generate-luks2-non-null-bytes-beyond-json0.img.sh new file mode 100755 index 00000000..7d466287 --- /dev/null +++ b/tests/generators/generate-luks2-non-null-bytes-beyond-json0.img.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with json area containing illegal bytes +# beyond well-formed json format. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +QUOTE="[Homer J. Simpson]: Keep looking shocked and move slowly towards the cake." +SPACE=20 + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + read -r json_str < $TMPDIR/json0 + json_len_orig=${#json_str} + json_len=$((json_len_orig+${#QUOTE}+SPACE)) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + printf '%s' "$QUOTE" | _dd of=$TMPDIR/json0 seek=$((json_len_orig+SPACE)) bs=1 conv=notrunc + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + chks_res0=$(read_sha256_checksum $TGT_IMG) + test "$chks0" = "$chks_res0" || exit 2 + + _dd if=$TMPDIR/json_res0 of=$TMPDIR/quote skip=$((json_len_orig+SPACE)) count=${#QUOTE} bs=1 + json_str_res0=$(head -c ${#QUOTE} $TMPDIR/quote) + test "$json_str_res0" = "$QUOTE" || exit 2 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-overlapping-areas-c0-json0.img.sh b/tests/generators/generate-luks2-overlapping-areas-c0-json0.img.sh new file mode 100755 index 00000000..c319ca37 --- /dev/null +++ b/tests/generators/generate-luks2-overlapping-areas-c0-json0.img.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with two exactly same areas in terms of 'offset' and 'length'. +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + # copy area 6 offset and length into area 7 + json_str=$(jq -c '.keyslots."7".area.offset = .keyslots."6".area.offset | + .keyslots."7".area.size = .keyslots."6".area.size' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c 'if (.keyslots."6".area.offset != .keyslots."7".area.offset) or (.keyslots."6".area.size != .keyslots."7".area.size) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-overlapping-areas-c1-json0.img.sh b/tests/generators/generate-luks2-overlapping-areas-c1-json0.img.sh new file mode 100755 index 00000000..244266f7 --- /dev/null +++ b/tests/generators/generate-luks2-overlapping-areas-c1-json0.img.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with one area incuded within another one (in terms of 'offset' + 'length') +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + # make area 7 being included in area 6 + json_str=$(jq -c '.keyslots."7".area.offset = (.keyslots."6".area.offset | tonumber + 1 | tostring ) | + .keyslots."7".area.size = ( .keyslots."6".area.size | tonumber - 1 | tostring)' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c 'if (.keyslots."7".area.offset != (.keyslots."6".area.offset | tonumber + 1 | tostring)) or + (.keyslots."7".area.size != (.keyslots."6".area.size | tonumber - 1 | tostring)) or + (.keyslots."7".area.size | tonumber <= 0) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/generate-luks2-overlapping-areas-c2-json0.img.sh b/tests/generators/generate-luks2-overlapping-areas-c2-json0.img.sh new file mode 100755 index 00000000..4c02008d --- /dev/null +++ b/tests/generators/generate-luks2-overlapping-areas-c2-json0.img.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +. lib.sh + +# +# *** Description *** +# +# generate primary header with one area slightly cross the boundary of another one +# +# secondary header is corrupted on purpose as well +# + +# $1 full target dir +# $2 full source luks2 image + +function prepare() +{ + cp $SRC_IMG $TGT_IMG + test -d $TMPDIR || mkdir $TMPDIR + read_luks2_json0 $TGT_IMG $TMPDIR/json0 + read_luks2_bin_hdr0 $TGT_IMG $TMPDIR/hdr0 + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr1 +} + +function generate() +{ + # make area 7 being included in area 6 + json_str=$(jq -c '.keyslots."7".area.offset = ([ .keyslots."6".area.offset, .keyslots."6".area.size ] | map(tonumber) | add - 1 | tostring)' $TMPDIR/json0) + test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2 + + write_luks2_json "$json_str" $TMPDIR/json0 + + merge_bin_hdr_with_json $TMPDIR/hdr0 $TMPDIR/json0 $TMPDIR/area0 + erase_checksum $TMPDIR/area0 + chks0=$(calc_sha256_checksum_file $TMPDIR/area0) + write_checksum $chks0 $TMPDIR/area0 + write_luks2_hdr0 $TMPDIR/area0 $TGT_IMG + kill_bin_hdr $TMPDIR/hdr1 + write_luks2_hdr1 $TMPDIR/hdr1 $TGT_IMG +} + +function check() +{ + read_luks2_bin_hdr1 $TGT_IMG $TMPDIR/hdr_res1 + local str_res1=$(head -c 6 $TMPDIR/hdr_res1) + test "$str_res1" = "VACUUM" || exit 2 + + read_luks2_json0 $TGT_IMG $TMPDIR/json_res0 + jq -c 'if .keyslots."7".area.offset != ([.keyslots."6".area.offset, .keyslots."6".area.size ] | map(tonumber) | add - 1 | tostring) + then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5 +} + +function cleanup() +{ + rm -f $TMPDIR/* + rm -fd $TMPDIR +} + +test $# -eq 2 || exit 1 + +TGT_IMG=$1/$(test_img_name $0) +SRC_IMG=$2 + +prepare +generate +check +cleanup diff --git a/tests/generators/lib.sh b/tests/generators/lib.sh new file mode 100644 index 00000000..95e11076 --- /dev/null +++ b/tests/generators/lib.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +# all in 512 bytes blocks +# LUKS2 with 16KiB header +LUKS2_HDR_SIZE=32 # 16 KiB +LUKS2_BIN_HDR_SIZE=8 # 4096 B +LUKS2_JSON_SIZE=$((LUKS2_HDR_SIZE-LUKS2_BIN_HDR_SIZE)) + +LUKS2_BIN_HDR_CHKS_OFFSET=0x1C0 +LUKS2_BIN_HDR_CHKS_LENGTH=64 + +[ -z "$srcdir" ] && srcdir="." +TMPDIR=$srcdir/tmp + +repeat_str() { + printf "$1"'%.0s' $(eval "echo {1.."$(($2))"}"); +} + +function strindex() +{ + local x="${1%%$2*}" + [[ $x = $1 ]] && echo -1 || echo ${#x} +} + +function test_img_name() +{ + local str=$(basename $1) + str=${str#generate-} + str=${str%%.sh} + echo $str +} + +function read_luks2_bin_hdr0() +{ + _dd if=$1 of=$2 bs=512 count=$LUKS2_BIN_HDR_SIZE +} + +function read_luks2_json0() +{ + _dd if=$1 of=$2 bs=512 skip=$LUKS2_BIN_HDR_SIZE count=$LUKS2_JSON_SIZE +} + +function read_luks2_bin_hdr1() +{ + _dd if=$1 of=$2 skip=$LUKS2_HDR_SIZE bs=512 count=$LUKS2_BIN_HDR_SIZE +} + +function read_luks2_json1() +{ + _dd if=$1 of=$2 bs=512 skip=$((LUKS2_BIN_HDR_SIZE+LUKS2_HDR_SIZE)) count=$LUKS2_JSON_SIZE +} + +function read_luks2_hdr_area0() +{ + _dd if=$1 of=$2 bs=512 count=$LUKS2_HDR_SIZE +} + +function read_luks2_hdr_area1() +{ + _dd if=$1 of=$2 bs=512 skip=$LUKS2_HDR_SIZE count=$LUKS2_HDR_SIZE +} + +function write_luks2_bin_hdr1() +{ + _dd if=$1 of=$2 bs=512 seek=$LUKS2_HDR_SIZE count=$LUKS2_BIN_HDR_SIZE conv=notrunc +} + +function write_luks2_hdr0() +{ + _dd if=$1 of=$2 bs=512 count=$LUKS2_HDR_SIZE conv=notrunc +} + +function write_luks2_hdr1() +{ + _dd if=$1 of=$2 bs=512 seek=$LUKS2_HDR_SIZE count=$LUKS2_HDR_SIZE conv=notrunc +} + +# 1 - json str +function write_luks2_json() +{ + local len=${#1} + printf '%s' "$1" | _dd of=$2 bs=1 count=$len conv=notrunc + _dd if=/dev/zero of=$2 bs=1 seek=$len count=$((LUKS2_JSON_SIZE*512-len)) +} + +function kill_bin_hdr() +{ + printf "VACUUM" | _dd of=$1 bs=1 conv=notrunc +} + +function erase_checksum() +{ + _dd if=/dev/zero of=$1 bs=1 seek=$(printf %d $LUKS2_BIN_HDR_CHKS_OFFSET) count=$LUKS2_BIN_HDR_CHKS_LENGTH conv=notrunc +} + +function read_sha256_checksum() +{ + _dd if=$1 bs=1 skip=$(printf %d $LUKS2_BIN_HDR_CHKS_OFFSET) count=32 | xxd -c 32 -p +} + +# 1 - string with checksum +function write_checksum() +{ + test $# -eq 2 || return 1 + test $((${#1}/2)) -le $LUKS2_BIN_HDR_CHKS_LENGTH || { echo "too long"; return 1; } + + echo $1 | xxd -r -p | _dd of=$2 bs=1 seek=$(printf %d $LUKS2_BIN_HDR_CHKS_OFFSET) conv=notrunc +} + +function calc_sha256_checksum_file() +{ + sha256sum $1 | cut -d ' ' -f 1 +} + +function calc_sha256_checksum_stdin() +{ + sha256sum - | cut -d ' ' -f 1 +} + +# 1 - bin +# 2 - json +# 3 - luks2_hdr_area +function merge_bin_hdr_with_json() +{ + _dd if=$1 of=$3 bs=512 count=$LUKS2_BIN_HDR_SIZE + _dd if=$2 of=$3 bs=512 seek=$LUKS2_BIN_HDR_SIZE count=$LUKS2_JSON_SIZE +} + +function _dd() +{ + dd $@ 2>/dev/null + #dd $@ +} diff --git a/tests/luks2-integrity-test b/tests/luks2-integrity-test new file mode 100755 index 00000000..ac5c94b3 --- /dev/null +++ b/tests/luks2-integrity-test @@ -0,0 +1,151 @@ +#!/bin/bash +# +# Test cryptsetup/authenticated encryption compatibility. +# +CRYPTSETUP=../src/cryptsetup +DEV_NAME=dmi_test +DEV=mode-test.img +PWD1=nHjJHjI23JK +KEY_FILE=key.img +FAST_PBKDF_OPT="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" + +dmremove() { # device + udevadm settle >/dev/null 2>&1 + dmsetup remove $1 >/dev/null 2>&1 +} + +cleanup() { + [ -b /dev/mapper/$DEV_NAME ] && dmremove $DEV_NAME + [ -b /dev/mapper/"$DEV_NAME"_dif ] && dmremove "$DEV_NAME"_dif + rm -f $DEV $KEY_FILE >/dev/null 2>&1 +} + +fail() +{ + echo + [ -n "$1" ] && echo "FAIL: $1" + cleanup + exit 100 +} + +skip() +{ + [ -n "$1" ] && echo "$1" + exit 77 +} + +add_device() { + cleanup + dd if=/dev/urandom of=$KEY_FILE bs=1 count=512 >/dev/null 2>&1 + dd if=/dev/zero of=$DEV bs=1M count=32 >/dev/null 2>&1 + sync +} + +status_check() # name value +{ + #$CRYPTSETUP status $DEV_NAME + X=$($CRYPTSETUP status $DEV_NAME | grep -m1 "$1" | sed -e 's/.*:[ \t]\+//' | cut -d' ' -f1) + if [ "$X" != "$2" ] ; then + echo "[status FAIL]" + echo " Expecting $1:$2 got \"$X\"." + fail + fi +} + +dump_check() # name value +{ + #$CRYPTSETUP luksDump $DEV + X=$($CRYPTSETUP luksDump $DEV | grep -m1 "$1" | sed -e 's/.*:[ \t]\+//' | cut -d' ' -f1) + if [ "$X" != "$2" ] ; then + echo "[dump FAIL]" + echo " Expecting $1:$2 got \"$X\"." + fail + fi +} + +int_check_sum() # alg checksum +{ + VSUM=$(sha256sum /dev/mapper/$DEV_NAME | cut -d' ' -f 1) + if [ "$VSUM" = "$2" ] ; then + echo -n "[CHECKSUM]" + else + echo "[FAIL]" + echo " Expecting $2 got $VSUM." + fail + fi +} + +int_error_detection() # alg int sector_size +{ + # FIXME: this is just a trivial failure + echo -n "[DETECT_CORRUPTION]" + echo -n "XXXXX" | dd of=$DEV bs=1M seek=28 count=1 conv=notrunc >/dev/null 2>&1 || fail "Cannot write to device." + $CRYPTSETUP open -d $KEY_FILE $DEV $DEV_NAME || fail "Cannot activate device." + dd if=/dev/mapper/$DEV_NAME of=/dev/null >/dev/null 2>&1 && fail "Error detection failed." + $CRYPTSETUP close $DEV_NAME || fail "Cannot deactivate device." +} + +intformat() # alg integrity integrity_out key_size int_key_size sector_size csum +{ + echo -n "[$1:$2:$4:$6]" + echo -n "[FORMAT]" + $CRYPTSETUP luksFormat --type luks2 -q -c $1 --integrity $2 --sector-size $6 -s $4 \ + $FAST_PBKDF_OPT -d $KEY_FILE $DEV >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo "[N/A]" + return + fi + dump_check "cipher" $1 + dump_check "sector" $6 + dump_check "integrity" $3 + dump_check "Key:" $(($4 + $5)) + echo -n "[ACTIVATE]" + $CRYPTSETUP open -d $KEY_FILE $DEV $DEV_NAME || fail "Cannot activate device." + status_check "cipher" $1 + status_check "sector size" $6 + status_check "integrity:" $3 + status_check "keysize:" $(($4 + $5)) + [ $5 -gt 0 ] && status_check "integrity keysize:" $5 + int_check_sum $1 $7 + echo -n "[REMOVE]" + $CRYPTSETUP close $DEV_NAME || fail "Cannot deactivate device." + int_error_detection + echo "[OK]" +} + + +[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." +[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped." +modprobe dm-integrity >/dev/null 2>&1 +dmsetup targets | grep integrity >/dev/null 2>&1 || skip "Cannot find dm-integrity target, test skipped." + +add_device + +intformat aes-xts-plain64 hmac-sha256 hmac\(sha256\) 256 256 512 ee501705a084cd0ab6f4a28014bcf62b8bfa3434de00b82743c50b3abf06232c +intformat aes-xts-random hmac-sha256 hmac\(sha256\) 256 256 512 492c2d1cc9e222a850c399bfef4ed5a86bf5afc59e54f0f0c7ba8e2a64548323 +intformat aes-xts-plain64 hmac-sha256 hmac\(sha256\) 512 256 512 ee501705a084cd0ab6f4a28014bcf62b8bfa3434de00b82743c50b3abf06232c +intformat aes-xts-random hmac-sha256 hmac\(sha256\) 512 256 512 492c2d1cc9e222a850c399bfef4ed5a86bf5afc59e54f0f0c7ba8e2a64548323 +intformat aes-xts-plain64 hmac-sha256 hmac\(sha256\) 256 256 4096 358d6beceddf593aff6b22c31684e0df9c226330aff5812e060950215217d21b +intformat aes-xts-random hmac-sha256 hmac\(sha256\) 256 256 4096 8c0463f5ac09613674bdf40b0ff6f985edbc3de04e51fdc688873cb333ef3cda +intformat aes-xts-plain64 hmac-sha256 hmac\(sha256\) 512 256 4096 358d6beceddf593aff6b22c31684e0df9c226330aff5812e060950215217d21b +intformat aes-xts-random hmac-sha256 hmac\(sha256\) 512 256 4096 8c0463f5ac09613674bdf40b0ff6f985edbc3de04e51fdc688873cb333ef3cda + +intformat aes-xts-plain64 hmac-sha512 hmac\(sha512\) 512 512 4096 9873d864fccb866521e79c9f0f75ad0c578d6bd7620399bbf4779e698c6e92fd +intformat aes-xts-random hmac-sha512 hmac\(sha512\) 512 512 4096 621f6c03f7361c2bf8f10059ae822339223f8471c750b0cf8584fba7134bd4a2 + +intformat aes-gcm-random aead aead 128 0 512 5f6f3f6be03c74d9aaaeaf40dd310c99a20e2786045f78a1fc6a0b189d231f57 +intformat aes-gcm-random aead aead 128 0 4096 358d6beceddf593aff6b22c31684e0df9c226330aff5812e060950215217d21b +intformat aes-gcm-random aead aead 256 0 512 5f6f3f6be03c74d9aaaeaf40dd310c99a20e2786045f78a1fc6a0b189d231f57 +intformat aes-gcm-random aead aead 256 0 4096 358d6beceddf593aff6b22c31684e0df9c226330aff5812e060950215217d21b + +intformat aes-ccm-random aead aead 152 0 512 288e5e9bc5be6c0bd2a74abbb72c7944da83198b5e3041dcf159e7ae250dafa8 +intformat aes-ccm-random aead aead 152 0 4096 7370c66a92708fb71b186931468be6aa9b26f4f88373b00b1c57360b9ee1304e +intformat aes-ccm-random aead aead 280 0 512 288e5e9bc5be6c0bd2a74abbb72c7944da83198b5e3041dcf159e7ae250dafa8 +intformat aes-ccm-random aead aead 280 0 4096 7370c66a92708fb71b186931468be6aa9b26f4f88373b00b1c57360b9ee1304e + +intformat chacha20-plain64 poly1305 poly1305 256 0 512 3f82eae753ff52a689ddc559c691bbdff838361bbe9a3ce8c7212e16e51b5dbe +intformat chacha20-random poly1305 poly1305 256 0 512 5f6f3f6be03c74d9aaaeaf40dd310c99a20e2786045f78a1fc6a0b189d231f57 +intformat chacha20-plain64 poly1305 poly1305 256 0 4096 7370c66a92708fb71b186931468be6aa9b26f4f88373b00b1c57360b9ee1304e +intformat chacha20-random poly1305 poly1305 256 0 4096 358d6beceddf593aff6b22c31684e0df9c226330aff5812e060950215217d21b + +cleanup diff --git a/tests/luks2-validation-test b/tests/luks2-validation-test new file mode 100755 index 00000000..8beff726 --- /dev/null +++ b/tests/luks2-validation-test @@ -0,0 +1,162 @@ +#!/bin/bash + +#turn on debug mode by following env. variable _DEBUG=1 + +PS4='$LINENO:' +CRYPTSETUP=../src/cryptsetup + +CRYPTSETUP_VALGRIND=../src/.libs/cryptsetup +CRYPTSETUP_LIB_VALGRIND=../lib/.libs + +DM_CRYPT_SECTOR=512 +LUKS2_HDR_SIZE=2112 # 16 KiB version, stored twice, including luks2 areas with keyslots + +START_DIR=$(pwd) + +IMG=luks2-backend.img +ORIG_IMG=luks2_valid_hdr.img +TST_IMGS=$START_DIR/luks2-images + +GEN_DIR=generators + +[ -z "$srcdir" ] && srcdir="." + +function remove_mapping() +{ + rm -rf $IMG $TST_IMGS >/dev/null 2>&1 +} + +function fail() +{ + [ -n "$1" ] && echo "$1" + echo "FAILED" + cd $START_DIR + remove_mapping + exit 2 +} + +function skip() +{ + [ -n "$1" ] && echo "$1" + exit 77 +} + +function prepare() # $1 dev1_size +{ + remove_mapping + + test -d $TST_IMGS || mkdir $TST_IMGS + + test -e $ORIG_IMG || xz -dkc $srcdir/$ORIG_IMG.xz >$ORIG_IMG + cp $ORIG_IMG $TST_IMGS + cp $ORIG_IMG $IMG +} + +function test_load() +{ + local _debug= + + test -z "$_DEBUG" || _debug="--debug" + + case "$1" in + R) + if [ -n "$_debug" ]; then + $CRYPTSETUP luksDump $_debug $IMG || fail "$2" + else + $CRYPTSETUP luksDump $_debug $IMG > /dev/null || fail "$2" + fi + ;; + F) + if [ -n "$_debug" ]; then + $CRYPTSETUP luksDump $_debug $IMG && fail "$2" + else + $CRYPTSETUP luksDump $_debug $IMG > /dev/null 2>&1 && fail "$2" + fi + ;; + *) + fail "Internal test error" + ;; + esac + +} + +function RUN() +{ + echo -n "Test image: $1..." + cp $TST_IMGS/$1 $IMG || fail "Missing test image" + test_load $2 "$3" + echo "OK" +} + +function valgrind_setup() +{ + which valgrind >/dev/null 2>&1 || fail "Cannot find valgrind." + [ ! -f $CRYPTSETUP_VALGRIND ] && fail "Unable to get location of cryptsetup executable." + export LD_LIBRARY_PATH="$CRYPTSETUP_LIB_VALGRIND:$LD_LIBRARY_PATH" +} + +function valgrind_run() +{ + INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@" +} + +[ -n "$VALG" ] && valgrind_setup && CRYPTSETUP=valgrind_run + +which jq >/dev/null || skip "Cannot find jq, test skipped." + +prepare + +echo "[0] Generating test headers" +cd $srcdir/$GEN_DIR +for scr in ./generate-*.sh; do + echo -n "$(basename $scr)..." + $scr $TST_IMGS $TST_IMGS/$ORIG_IMG || fail "Header generator $scr failed: '$?'" + echo "done" +done +cd $START_DIR + +echo "[1] Test basic auto-recovery" +RUN luks2-invalid-checksum-hdr0.img "R" "Failed to recover from trivial header corruption at offset 0" +# TODO: check epoch is incresed after recovery +# TODO: check only sectors related to corrupted hdr at offset 0 are written (dmstats tool/differ.c) + +RUN luks2-invalid-checksum-hdr1.img "R" "Failed to recover from trivial header corruption at offset 16384" +# TODO: check epoch is incresed after recovery +# TODO: check only sectors related to corrupted hdr at offset 16384 are written (dmstats tool/differ.c) + +RUN luks2-invalid-checksum-both-hdrs.img "F" "Failed to recognise corrupted header beyond repair" + +echo "[2] Test ability to auto-correct mallformed json area" +RUN luks2-corrupted-hdr0-with-correct-chks.img "R" "Failed to auto correct malformed json area at offset 512" +# TODO: check epoch is incresed after recovery +# TODO: check only sectors related to corrupted hdr at offset 0 are written (dmstats tool/differ.c) + +RUN luks2-corrupted-hdr1-with-correct-chks.img "R" "Failed to auto correct malformed json area at offset 16896" +# TODO: check epoch is incresed after recovery +# TODO: check only sectors related to corrupted hdr at offset 16384 are written (dmstats tool/differ.c) + +RUN luks2-correct-full-json0.img "R" "Failed to parse full and correct json area" +# TODO: detect noop (norecovery, epoch untouched) +# TODO: check epoch is NOT incresed after recovery of secondary header + +# Secondary header is always broken in following tests +echo "[3] Test LUKS2 json area restrictions" +RUN luks2-non-null-byte-beyond-json0.img "F" "Failed to detect illegal data right beyond json data string" +RUN luks2-non-null-bytes-beyond-json0.img "F" "Failed to detect illegal data in json area" +RUN luks2-missing-trailing-null-byte-json0.img "F" "Failed to detect missing terminal null byte" +RUN luks2-invalid-opening-char-json0.img "F" "Failed to detect invalid opening character in json area" +RUN luks2-invalid-object-type-json0.img "F" "Failed to detect invalid json object type" +RUN luks2-overlapping-areas-c0-json0.img "F" "Failed to detect two exactly same area specifications" +RUN luks2-overlapping-areas-c1-json0.img "F" "Failed to detect two intersecting area specifications" +RUN luks2-overlapping-areas-c2-json0.img "F" "Failed to detect two slightly intersecting area specifications" +RUN luks2-area-in-json-hdr-space-json0.img "F" "Failed to detect area referencing LUKS2 header space" +RUN luks2-missing-keyslot-referenced-in-digest.img "F" "Failed to detect missing keyslot referenced in digest" +RUN luks2-missing-segment-referenced-in-digest.img "F" "Failed to detect missing segment referenced in digest" +RUN luks2-missing-keyslot-referenced-in-token.img "F" "Failed to detect missing keyslots referenced in token" +RUN luks2-invalid-keyslots-size-c0.img "F" "Failed to detect too large keyslots_size in config section" +RUN luks2-invalid-keyslots-size-c1.img "F" "Failed to detect unaligned keyslots_size in config section" +RUN luks2-invalid-keyslots-size-c2.img "F" "Failed to detect too small keyslots_size config section" +RUN luks2-invalid-json-size-c0.img "F" "Failed to detect invalid json_size config section" +RUN luks2-invalid-json-size-c1.img "F" "Failed to detect invalid json_size config section" + +remove_mapping diff --git a/tests/luks2_header_file.xz b/tests/luks2_header_file.xz new file mode 100644 index 00000000..2dc3a1f1 Binary files /dev/null and b/tests/luks2_header_file.xz differ diff --git a/tests/luks2_header_requirements.xz b/tests/luks2_header_requirements.xz new file mode 100644 index 00000000..083c52a5 Binary files /dev/null and b/tests/luks2_header_requirements.xz differ diff --git a/tests/luks2_header_requirements_free.xz b/tests/luks2_header_requirements_free.xz new file mode 100644 index 00000000..6cdacd76 Binary files /dev/null and b/tests/luks2_header_requirements_free.xz differ diff --git a/tests/luks2_keyslot_unassigned.img.xz b/tests/luks2_keyslot_unassigned.img.xz new file mode 100644 index 00000000..ff2dc279 Binary files /dev/null and b/tests/luks2_keyslot_unassigned.img.xz differ diff --git a/tests/luks2_valid_hdr.img.xz b/tests/luks2_valid_hdr.img.xz new file mode 100644 index 00000000..12e09d1b Binary files /dev/null and b/tests/luks2_valid_hdr.img.xz differ