X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tests%2Fapi-test.c;h=2703ceb84853af4a2e2a62e705553ac584cdb9a5;hb=7835b365a730ebc721460166cce9a03cabde4677;hp=38526827ff11feb41662b6d6de49b8f53250584d;hpb=1bf26b9a90e5f0d18436cf55123ee5e05855232a;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/tests/api-test.c b/tests/api-test.c index 3852682..2703ceb 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -14,7 +14,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include @@ -29,6 +29,7 @@ #include #include +#include "luks.h" #include "libcryptsetup.h" #include "utils_loop.h" @@ -43,7 +44,18 @@ #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 EVL_HEADER_1 "evil_hdr-luks_hdr_damage" +#define EVL_HEADER_2 "evil_hdr-payload_overwrite" +#define EVL_HEADER_3 "evil_hdr-stripes_payload_dmg" +#define EVL_HEADER_4 "evil_hdr-small_luks_device" +#define VALID_HEADER "valid_header_file" +#define BACKUP_FILE "csetup_backup_file" #define IMAGE1 "compatimage.img" #define IMAGE_EMPTY "empty.img" @@ -57,6 +69,17 @@ #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 SECTOR_SHIFT 9L +#define SECTOR_SIZE 512 +#define TST_LOOP_FILE_SIZE (((1<<20)*50)>>SECTOR_SHIFT) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define DIV_ROUND_UP_MODULO(n,d) (DIV_ROUND_UP(n,d)*(d)) +#define LUKS_PHDR_SIZE_B 1024 + static int _debug = 0; static int _verbose = 1; @@ -65,16 +88,103 @@ static int global_lines = 0; static char *DEVICE_1 = NULL; static char *DEVICE_2 = NULL; +static char *THE_LOOP_DEV = NULL; + +static char *tmp_file_1 = NULL; +static char *test_loop_file = NULL; +static uint64_t t_dev_offset = 0; + +static int _system(const char*, int); // Helpers +static int device_size(const char *device, uint64_t *size) +{ + int devfd, r = 0; + + devfd = open(device, O_RDONLY); + if(devfd == -1) + return -EINVAL; + + if (ioctl(devfd, BLKGETSIZE64, size) < 0) + r = -EINVAL; + close(devfd); + return r; +} + +static int get_luks_offsets(int metadata_device, + size_t keylength, + unsigned int alignpayload_sec, + unsigned int alignoffset_sec, + uint64_t *r_header_size, + uint64_t *r_payload_offset) +{ + int i; + uint64_t current_sector; + uint32_t sectors_per_stripes_set; + + if (!keylength) + return -1; + + sectors_per_stripes_set = DIV_ROUND_UP(keylength*LUKS_STRIPES, SECTOR_SIZE); + printf("sectors_per_stripes %" PRIu32 "\n", sectors_per_stripes_set); + current_sector = DIV_ROUND_UP_MODULO(DIV_ROUND_UP(LUKS_PHDR_SIZE_B, SECTOR_SIZE), + LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); + for(i=0;i < (LUKS_NUMKEYS - 1);i++) + current_sector = DIV_ROUND_UP_MODULO(current_sector + sectors_per_stripes_set, + LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); + if (r_header_size) + *r_header_size = current_sector + sectors_per_stripes_set; + + current_sector = DIV_ROUND_UP_MODULO(current_sector + sectors_per_stripes_set, + LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE); + + if (r_payload_offset) { + if (metadata_device) + *r_payload_offset = alignpayload_sec; + else + *r_payload_offset = DIV_ROUND_UP_MODULO(current_sector, alignpayload_sec) + + alignoffset_sec; + } + + return 0; +} + +/* + * Creates dm-linear target over the test loop device. Offset is held in + * global variables so that size can be tested whether it fits into remaining + * size of the loop device or not + */ +static int create_dmdevice_over_loop(const char *dm_name, const uint64_t size) +{ + char cmd[128]; + int r; + uint64_t r_size; + + if(device_size(THE_LOOP_DEV, &r_size) < 0 || r_size <= t_dev_offset || !size) + return -1; + if ((r_size - t_dev_offset) < size) { + printf("No enough space on backing loop device\n."); + return -2; + } + snprintf(cmd, sizeof(cmd), + "dmsetup create %s --table \"0 %" PRIu64 " linear %s %" PRIu64 "\"", + dm_name, size, THE_LOOP_DEV, t_dev_offset); + if (!(r = _system(cmd, 1))) { + t_dev_offset += size; + } + return r; +} + +// TODO some utility to remove dmdevice over the loop file + // Get key from kernel dm mapping table using dm-ioctl static int _get_key_dm(const char *name, char *buffer, unsigned int buffer_size) { struct dm_task *dmt; struct dm_info dmi; uint64_t start, length; - char *target_type, *rcipher, *key, *params; + char *target_type, *key, *params; void *next = NULL; int r = -EINVAL; @@ -93,7 +203,7 @@ static int _get_key_dm(const char *name, char *buffer, unsigned int buffer_size) if (!target_type || strcmp(target_type, "crypt") != 0) goto out; - rcipher = strsep(¶ms, " "); + (void)strsep(¶ms, " "); /* rcipher */ key = strsep(¶ms, " "); if (buffer_size <= strlen(key)) @@ -129,7 +239,7 @@ static void _remove_keyfiles(void) } // Decode key from its hex representation -static int crypt_decode_key(char *key, char *hex, unsigned int size) +static int crypt_decode_key(char *key, const char *hex, unsigned int size) { char buffer[3]; char *endp; @@ -153,7 +263,7 @@ static int crypt_decode_key(char *key, char *hex, unsigned int size) return 0; } -static void cmdLineLog(int level, char *msg) +static void cmdLineLog(int level, const char *msg) { strncat(global_log, msg, sizeof(global_log) - strlen(global_log)); global_lines++; @@ -161,19 +271,47 @@ static void cmdLineLog(int level, char *msg) static void new_log(int level, const char *msg, void *usrptr) { - cmdLineLog(level, (char*)msg); + cmdLineLog(level, msg); } -static void reset_log() +static void reset_log(void) { memset(global_log, 0, sizeof(global_log)); global_lines = 0; } -static void _system(const char *command, int warn) +static int _system(const char *command, int warn) { - if (system(command) < 0 && warn) + int r; + if ((r=system(command)) < 0 && warn) printf("System command failed: %s", command); + return r; +} + +static void _cleanup_dmdevices(void) +{ + struct stat st; + + if (!stat(DMDIR H_DEVICE, &st)) { + _system("dmsetup remove " H_DEVICE, 0); + } + if (!stat(DMDIR H_DEVICE_WRONG, &st)) { + _system("dmsetup remove " H_DEVICE_WRONG, 0); + } + if (!stat(DMDIR L_DEVICE_0S, &st)) { + _system("dmsetup remove " L_DEVICE_0S, 0); + } + if (!stat(DMDIR L_DEVICE_1S, &st)) { + _system("dmsetup remove " L_DEVICE_1S, 0); + } + if (!stat(DMDIR L_DEVICE_WRONG, &st)) { + _system("dmsetup remove " L_DEVICE_WRONG, 0); + } + if (!stat(DMDIR L_DEVICE_OK, &st)) { + _system("dmsetup remove " L_DEVICE_OK, 0); + } + + t_dev_offset = 0; } static void _cleanup(void) @@ -194,6 +332,11 @@ static void _cleanup(void) 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); @@ -201,12 +344,64 @@ static void _cleanup(void) crypt_loop_detach(DEVICE_2); _system("rm -f " IMAGE_EMPTY, 0); + _system("rm -f " IMAGE1, 0); + + remove(test_loop_file); + remove(tmp_file_1); + + remove(EVL_HEADER_1); + remove(EVL_HEADER_2); + remove(EVL_HEADER_3); + remove(EVL_HEADER_4); + remove(VALID_HEADER); + remove(BACKUP_FILE); + _remove_keyfiles(); + + free(tmp_file_1); + free(test_loop_file); + free(THE_LOOP_DEV); + free(DEVICE_1); + free(DEVICE_2); } 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", + test_loop_file, SECTOR_SIZE, TST_LOOP_FILE_SIZE); + if (_system(cmd, 1)) + return 1; + + if (!THE_LOOP_DEV) + THE_LOOP_DEV = crypt_loop_get_device(); + if (!THE_LOOP_DEV) { + printf("Cannot find free loop device.\n"); + return 1; + } + if (crypt_loop_device(THE_LOOP_DEV)) { + 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", + 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); @@ -232,10 +427,23 @@ static int _setup(void) fd = crypt_loop_attach(DEVICE_2, IMAGE_EMPTY, 0, 0, &ro); close(fd); } + /* Keymaterial offset is less than 8 sectors */ + _system(" [ ! -e " EVL_HEADER_1 " ] && bzip2 -dk " EVL_HEADER_1 ".bz2", 1); + /* keymaterial offset aims into payload area */ + _system(" [ ! -e " EVL_HEADER_2 " ] && bzip2 -dk " EVL_HEADER_2 ".bz2", 1); + /* keymaterial offset is valid, number of stripes causes payload area to be overwriten */ + _system(" [ ! -e " EVL_HEADER_3 " ] && bzip2 -dk " EVL_HEADER_3 ".bz2", 1); + /* luks device header for data and header on same device. payloadOffset is greater than + * device size (crypt_load() test) */ + _system(" [ ! -e " EVL_HEADER_4 " ] && bzip2 -dk " EVL_HEADER_4 ".bz2", 1); + /* valid header: payloadOffset=4096, key_size=32, + * volume_key = bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a */ + _system(" [ ! -e " VALID_HEADER " ] && bzip2 -dk " VALID_HEADER ".bz2", 1); + return 0; } -void check_ok(int status, int line, const char *func) +static void check_ok(int status, int line, const char *func) { char buf[256]; @@ -247,7 +455,7 @@ void check_ok(int status, int line, const char *func) } } -void check_ko(int status, int line, const char *func) +static void check_ko(int status, int line, const char *func) { char buf[256]; @@ -261,14 +469,14 @@ void check_ko(int status, int line, const char *func) printf(" => errno %d, errmsg: %s\n", status, buf); } -void check_equal(int line, const char *func) +static void check_equal(int line, const char *func) { printf("FAIL line %d [%s]: expected equal values differs.\n", line, func); _cleanup(); exit(-1); } -void xlog(const char *msg, const char *tst, const char *func, int line, const char *txt) +static void xlog(const char *msg, const char *tst, const char *func, int line, const char *txt) { if (_verbose) { if (txt) @@ -277,6 +485,8 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch printf(" [%s,%s:%d] %s\n", msg, func, line, tst); } } + +/* crypt_device context must be "cd" to parse error properly here */ #define OK_(x) do { xlog("(success)", #x, __FUNCTION__, __LINE__, NULL); \ check_ok((x), __LINE__, __FUNCTION__); \ } while(0) @@ -289,310 +499,6 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch #define RUN_(x, y) do { printf("%s: %s\n", #x, (y)); x(); } while (0) -#if 0 -static int yesDialog(char *msg) -{ - return 1; -} - -static struct interface_callbacks cmd_icb = { - .yesDialog = yesDialog, - .log = cmdLineLog, -}; - -// OLD API TESTS -static void LuksUUID(void) -{ - struct crypt_options co = { .icb = &cmd_icb }; - - co.device = DEVICE_EMPTY; - EQ_(crypt_luksUUID(&co), -EINVAL); - - co.device = DEVICE_ERROR; - EQ_(crypt_luksUUID(&co), -EINVAL); - - reset_log(); - co.device = DEVICE_1; - OK_(crypt_luksUUID(&co)); - EQ_(strlen(global_log), 37); /* UUID + "\n" */ - EQ_(strncmp(global_log, DEVICE_1_UUID, strlen(DEVICE_1_UUID)), 0); - -} - -static void IsLuks(void) -{ - struct crypt_options co = { .icb = &cmd_icb }; - - co.device = DEVICE_EMPTY; - EQ_(crypt_isLuks(&co), -EINVAL); - - co.device = DEVICE_ERROR; - EQ_(crypt_isLuks(&co), -EINVAL); - - co.device = DEVICE_1; - OK_(crypt_isLuks(&co)); -} - -static void LuksOpen(void) -{ - struct crypt_options co = { - .name = CDEVICE_1, - //.passphrase = "blabla", - .icb = &cmd_icb, - }; - - OK_(_prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); - co.key_file = KEYFILE1; - - co.device = DEVICE_EMPTY; - EQ_(crypt_luksOpen(&co), -EINVAL); - - co.device = DEVICE_ERROR; - EQ_(crypt_luksOpen(&co), -EINVAL); - - co.device = DEVICE_1; - OK_(crypt_luksOpen(&co)); - FAIL_(crypt_luksOpen(&co), "already open"); - - _remove_keyfiles(); -} - -static void query_device(void) -{ - struct crypt_options co = {.icb = &cmd_icb }; - - co.name = CDEVICE_WRONG; - EQ_(crypt_query_device(&co), 0); - - co.name = CDEVICE_1; - EQ_(crypt_query_device(&co), 1); - - OK_(strncmp(crypt_get_dir(), DMDIR, 11)); - OK_(strcmp(co.cipher, "aes-cbc-essiv:sha256")); - EQ_(co.key_size, 16); - EQ_(co.offset, 1032); - EQ_(co.flags & CRYPT_FLAG_READONLY, 0); - EQ_(co.skip, 0); - crypt_put_options(&co); -} - -static void remove_device(void) -{ - int fd; - struct crypt_options co = {.icb = &cmd_icb }; - - co.name = CDEVICE_WRONG; - EQ_(crypt_remove_device(&co), -ENODEV); - - fd = open(DMDIR CDEVICE_1, O_RDONLY); - co.name = CDEVICE_1; - FAIL_(crypt_remove_device(&co), "device busy"); - close(fd); - - OK_(crypt_remove_device(&co)); -} - -static void LuksFormat(void) -{ - struct crypt_options co = { - .device = DEVICE_2, - .key_size = 256 / 8, - .key_slot = -1, - .cipher = "aes-cbc-essiv:sha256", - .hash = "sha1", - .flags = 0, - .iteration_time = 10, - .align_payload = 0, - .icb = &cmd_icb, - }; - - OK_(_prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); - - co.new_key_file = KEYFILE1; - co.device = DEVICE_ERROR; - FAIL_(crypt_luksFormat(&co), "error device"); - - co.device = DEVICE_2; - OK_(crypt_luksFormat(&co)); - - co.new_key_file = NULL; - co.key_file = KEYFILE1; - co.name = CDEVICE_2; - OK_(crypt_luksOpen(&co)); - OK_(crypt_remove_device(&co)); - _remove_keyfiles(); -} - -static void LuksKeyGame(void) -{ - int i; - struct crypt_options co = { - .device = DEVICE_2, - .key_size = 256 / 8, - .key_slot = -1, - .cipher = "aes-cbc-essiv:sha256", - .hash = "sha1", - .flags = 0, - .iteration_time = 10, - .align_payload = 0, - .icb = &cmd_icb, - }; - - OK_(_prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); - OK_(_prepare_keyfile(KEYFILE2, KEY2, strlen(KEY2))); - - co.new_key_file = KEYFILE1; - co.device = DEVICE_2; - co.key_slot = 8; - FAIL_(crypt_luksFormat(&co), "wrong slot #"); - - co.key_slot = 7; // last slot - OK_(crypt_luksFormat(&co)); - - co.new_key_file = KEYFILE1; - co.key_file = KEYFILE1; - co.key_slot = 8; - FAIL_(crypt_luksAddKey(&co), "wrong slot #"); - co.key_slot = 7; - FAIL_(crypt_luksAddKey(&co), "slot already used"); - - co.key_slot = 6; - OK_(crypt_luksAddKey(&co)); - - co.key_file = KEYFILE2 "blah"; - co.key_slot = 5; - FAIL_(crypt_luksAddKey(&co), "keyfile not found"); - - co.new_key_file = KEYFILE2; // key to add - co.key_file = KEYFILE1; - co.key_slot = -1; - for (i = 0; i < 6; i++) - OK_(crypt_luksAddKey(&co)); //FIXME: EQ_(i)? - - FAIL_(crypt_luksAddKey(&co), "all slots full"); - - // REMOVE KEY - co.new_key_file = KEYFILE1; // key to remove - co.key_file = NULL; - co.key_slot = 8; // should be ignored - // only 2 slots should use KEYFILE1 - OK_(crypt_luksRemoveKey(&co)); - OK_(crypt_luksRemoveKey(&co)); - FAIL_(crypt_luksRemoveKey(&co), "no slot with this passphrase"); - - co.new_key_file = KEYFILE2 "blah"; - co.key_file = NULL; - FAIL_(crypt_luksRemoveKey(&co), "keyfile not found"); - - // KILL SLOT - co.new_key_file = NULL; - co.key_file = NULL; - co.key_slot = 8; - FAIL_(crypt_luksKillSlot(&co), "wrong slot #"); - co.key_slot = 7; - FAIL_(crypt_luksKillSlot(&co), "slot already wiped"); - - co.key_slot = 5; - OK_(crypt_luksKillSlot(&co)); - - _remove_keyfiles(); -} - -size_t _get_device_size(const char *device) -{ - unsigned long size = 0; - int fd; - - fd = open(device, O_RDONLY); - if (fd == -1) - return 0; - (void)ioctl(fd, BLKGETSIZE, &size); - close(fd); - - return size; -} - -void DeviceResizeGame(void) -{ - size_t orig_size; - struct crypt_options co = { - .name = CDEVICE_2, - .device = DEVICE_2, - .key_size = 128 / 8, - .cipher = "aes-cbc-plain", - .hash = "sha1", - .offset = 333, - .skip = 0, - .icb = &cmd_icb, - }; - - orig_size = _get_device_size(DEVICE_2); - - OK_(_prepare_keyfile(KEYFILE2, KEY2, strlen(KEY2))); - - co.key_file = KEYFILE2; - co.size = 1000; - OK_(crypt_create_device(&co)); - EQ_(_get_device_size(DMDIR CDEVICE_2), 1000); - - co.size = 2000; - OK_(crypt_resize_device(&co)); - EQ_(_get_device_size(DMDIR CDEVICE_2), 2000); - - co.size = 0; - OK_(crypt_resize_device(&co)); - EQ_(_get_device_size(DMDIR CDEVICE_2), (orig_size - 333)); - co.size = 0; - co.offset = 444; - co.skip = 555; - co.cipher = "aes-cbc-essiv:sha256"; - OK_(crypt_update_device(&co)); - EQ_(_get_device_size(DMDIR CDEVICE_2), (orig_size - 444)); - - memset(&co, 0, sizeof(co)); - co.icb = &cmd_icb, - co.name = CDEVICE_2; - EQ_(crypt_query_device(&co), 1); - EQ_(strcmp(co.cipher, "aes-cbc-essiv:sha256"), 0); - EQ_(co.key_size, 128 / 8); - EQ_(co.offset, 444); - EQ_(co.skip, 555); - crypt_put_options(&co); - - // dangerous switch device still works - memset(&co, 0, sizeof(co)); - co.name = CDEVICE_2, - co.device = DEVICE_1; - co.key_file = KEYFILE2; - co.key_size = 128 / 8; - co.cipher = "aes-cbc-plain"; - co.hash = "sha1"; - co.icb = &cmd_icb; - OK_(crypt_update_device(&co)); - - memset(&co, 0, sizeof(co)); - co.icb = &cmd_icb, - co.name = CDEVICE_2; - EQ_(crypt_query_device(&co), 1); - EQ_(strcmp(co.cipher, "aes-cbc-plain"), 0); - EQ_(co.key_size, 128 / 8); - EQ_(co.offset, 0); - EQ_(co.skip, 0); - // This expect lookup returns prefered /dev/loopX - EQ_(strcmp(co.device, DEVICE_1), 0); - crypt_put_options(&co); - - memset(&co, 0, sizeof(co)); - co.icb = &cmd_icb, - co.name = CDEVICE_2; - OK_(crypt_remove_device(&co)); - - _remove_keyfiles(); -} -#endif - -// NEW API tests - static void AddDevicePlain(void) { struct crypt_device *cd; @@ -600,19 +506,46 @@ static void AddDevicePlain(void) .hash = "sha1", .skip = 0, .offset = 0, + .size = 0 }; int fd; char key[128], key2[128], path[128]; - char *passphrase = PASSPHRASE; - char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + const char *passphrase = PASSPHRASE; + // hashed hex version of PASSPHRASE + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; size_t key_size = strlen(mk_hex) / 2; - char *cipher = "aes"; - char *cipher_mode = "cbc-essiv:sha256"; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; - crypt_decode_key(key, mk_hex, key_size); + uint64_t size, r_size; + crypt_decode_key(key, mk_hex, key_size); FAIL_(crypt_init(&cd, ""), "empty device string"); + FAIL_(crypt_init(&cd, DEVICE_WRONG), "nonexistent device name "); + FAIL_(crypt_init(&cd, DEVICE_CHAR), "character device as backing device"); + OK_(crypt_init(&cd, tmp_file_1)); + crypt_free(cd); + + // test crypt_format, crypt_get_cipher, crypt_get_cipher_mode, crypt_get_volume_key_size + OK_(crypt_init(&cd,DEVICE_1)); + params.skip = 3; + params.offset = 42; + FAIL_(crypt_format(cd,CRYPT_PLAIN,NULL,cipher_mode,NULL,NULL,key_size,¶ms),"cipher param is null"); + FAIL_(crypt_format(cd,CRYPT_PLAIN,cipher,NULL,NULL,NULL,key_size,¶ms),"cipher_mode param is null"); + OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); + OK_(strcmp(cipher_mode,crypt_get_cipher_mode(cd))); + OK_(strcmp(cipher,crypt_get_cipher(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); + EQ_(params.skip, crypt_get_iv_offset(cd)); + EQ_(params.offset, crypt_get_data_offset(cd)); + params.skip = 0; + params.offset = 0; + + // crypt_set_uuid() + FAIL_(crypt_set_uuid(cd,DEVICE_1_UUID),"can't set uuid to plain device"); + + crypt_free(cd); // default is "plain" hash - no password hash OK_(crypt_init(&cd, DEVICE_1)); @@ -620,12 +553,87 @@ static void AddDevicePlain(void) FAIL_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0), "cannot verify key with plain"); OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); - // FIXME: this should get key from active device? - //OK_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key2, &key_size, passphrase, strlen(passphrase))); - //OK_(memcmp(key, key2, key_size)); OK_(crypt_deactivate(cd, CDEVICE_1)); crypt_free(cd); + // test boundaries in offset parameter + device_size(DEVICE_1,&size); + params.hash = NULL; + // zero sectors length + params.offset = size >> SECTOR_SHIFT; + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + EQ_(crypt_get_data_offset(cd),params.offset); + // device size is 0 sectors + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0), "invalid device size (0 blocks)"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + // data part of crypt device is of 1 sector size + params.offset = (size >> SECTOR_SHIFT) - 1; + crypt_free(cd); + + OK_(crypt_init(&cd, DEVICE_1)); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + snprintf(path, sizeof(path), "%s/%s", crypt_get_dir(), CDEVICE_1); + if (device_size(path, &r_size) >= 0) + EQ_(r_size>>SECTOR_SHIFT, 1); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // size > device_size + params.offset = 0; + params.size = (size >> SECTOR_SHIFT) + 1; + crypt_init(&cd, DEVICE_1); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0),"Device too small"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // offset == device_size (autodetect size) + params.offset = (size >> SECTOR_SHIFT); + params.size = 0; + crypt_init(&cd, DEVICE_1); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0),"Device too small"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // offset == device_size (user defined size) + params.offset = (size >> SECTOR_SHIFT); + params.size = 123; + crypt_init(&cd, DEVICE_1); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0),"Device too small"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // offset+size > device_size + params.offset = 42; + params.size = (size >> SECTOR_SHIFT) - params.offset + 1; + crypt_init(&cd, DEVICE_1); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + FAIL_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0),"Offset and size are beyond device real size"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // offset+size == device_size + params.offset = 42; + params.size = (size >> SECTOR_SHIFT) - params.offset; + crypt_init(&cd, DEVICE_1); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, passphrase, strlen(passphrase), 0)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + if (!device_size(path, &r_size)) + EQ_((r_size >> SECTOR_SHIFT),params.size); + OK_(crypt_deactivate(cd,CDEVICE_1)); + + crypt_free(cd); + params.hash = "sha1"; + params.offset = 0; + params.size = 0; + params.skip = 0; + // Now use hashed password OK_(crypt_init(&cd, DEVICE_1)); OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); @@ -642,10 +650,103 @@ static void AddDevicePlain(void) close(fd); OK_(crypt_deactivate(cd, CDEVICE_1)); EQ_(crypt_status(cd, CDEVICE_1), CRYPT_INACTIVE); + crypt_free(cd); + + // crypt_init_by_name_and_header + OK_(crypt_init(&cd,DEVICE_1)); + OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + crypt_free(cd); + + FAIL_(crypt_init_by_name_and_header(&cd, CDEVICE_1, H_DEVICE),"can't init plain device by header device"); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(strcmp(cipher_mode,crypt_get_cipher_mode(cd))); + OK_(strcmp(cipher,crypt_get_cipher(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); + EQ_(params.skip, crypt_get_iv_offset(cd)); + EQ_(params.offset, crypt_get_data_offset(cd)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + OK_(crypt_init(&cd,DEVICE_1)); + OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); + params.size = 0; + params.offset = 0; + + // crypt_set_data_device + FAIL_(crypt_set_data_device(cd,H_DEVICE),"can't set data device for plain device"); + + // crypt_get_type + OK_(strcmp(crypt_get_type(cd),CRYPT_PLAIN)); OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + // crypt_resize() + OK_(crypt_resize(cd,CDEVICE_1,size>>SECTOR_SHIFT)); // same size + if (!device_size(path,&r_size)) + EQ_(r_size, size); + + // size overlaps + FAIL_(crypt_resize(cd, CDEVICE_1, ULLONG_MAX),"Backing device is too small"); + FAIL_(crypt_resize(cd, CDEVICE_1, (size>>SECTOR_SHIFT)+1),"crypt device overlaps backing device"); + + // resize ok + OK_(crypt_resize(cd,CDEVICE_1, 123)); + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, 123); + OK_(crypt_resize(cd,CDEVICE_1,0)); // full size (autodetect) + if (!device_size(path,&r_size)) + EQ_(r_size, size); + OK_(crypt_deactivate(cd,CDEVICE_1)); + EQ_(crypt_status(cd,CDEVICE_1),CRYPT_INACTIVE); + crypt_free(cd); + + // offset tests + OK_(crypt_init(&cd,DEVICE_1)); + params.offset = 42; + params.size = (size>>SECTOR_SHIFT) - params.offset - 10; + OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); + OK_(crypt_activate_by_volume_key(cd,CDEVICE_1,key,key_size,0)); + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, params.size); + // resize to fill remaining capacity + OK_(crypt_resize(cd,CDEVICE_1,params.size + 10)); + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, params.size + 10); + + // 1 sector beyond real size + FAIL_(crypt_resize(cd,CDEVICE_1,params.size + 11), "new device size overlaps backing device"); // with respect to offset + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, params.size + 10); + EQ_(crypt_status(cd,CDEVICE_1),CRYPT_ACTIVE); + fd = open(path, O_RDONLY); + close(fd); + OK_(fd < 0); + + // resize to minimal size + OK_(crypt_resize(cd,CDEVICE_1, 1)); // minimal device size + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, 1); + // use size of backing device (autodetect with respect to offset) + OK_(crypt_resize(cd,CDEVICE_1,0)); + if (!device_size(path,&r_size)) + EQ_(r_size>>SECTOR_SHIFT, (size >> SECTOR_SHIFT)- 42); + OK_(crypt_deactivate(cd,CDEVICE_1)); + crypt_free(cd); + + params.size = 0; + params.offset = 0; + OK_(crypt_init(&cd,DEVICE_1)); + OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); + OK_(crypt_activate_by_volume_key(cd,CDEVICE_1,key,key_size,0)); + + // suspend/resume tests + FAIL_(crypt_suspend(cd,CDEVICE_1),"cannot suspend plain device"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + FAIL_(crypt_resume_by_passphrase(cd,CDEVICE_1,CRYPT_ANY_SLOT,passphrase, strlen(passphrase)),"cannot resume plain device"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + // retrieve volume key check memset(key2, 0, key_size); key_size--; @@ -657,17 +758,30 @@ static void AddDevicePlain(void) OK_(memcmp(key, key2, key_size)); OK_(strcmp(cipher, crypt_get_cipher(cd))); OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); - EQ_(key_size, crypt_get_volume_key_size(cd)); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); EQ_(0, crypt_get_data_offset(cd)); OK_(crypt_deactivate(cd, CDEVICE_1)); // now with keyfile OK_(_prepare_keyfile(KEYFILE1, KEY1, strlen(KEY1))); + OK_(_prepare_keyfile(KEYFILE2, KEY2, strlen(KEY2))); FAIL_(crypt_activate_by_keyfile(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, 0), "cannot verify key with plain"); EQ_(0, crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0)); EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); OK_(crypt_deactivate(cd, CDEVICE_1)); _remove_keyfiles(); + crypt_free(cd); + + OK_(crypt_init(&cd,DEVICE_1)); + OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); + + // crypt_keyslot_*() + FAIL_(crypt_keyslot_add_by_passphrase(cd,CRYPT_ANY_SLOT,passphrase,strlen(passphrase),passphrase,strlen(passphrase)), "can't add keyslot to plain device"); + FAIL_(crypt_keyslot_add_by_volume_key(cd,CRYPT_ANY_SLOT ,key,key_size,passphrase,strlen(passphrase)),"can't add keyslot to plain device"); + FAIL_(crypt_keyslot_add_by_keyfile(cd,CRYPT_ANY_SLOT,KEYFILE1,strlen(KEY1),KEYFILE2,strlen(KEY2)),"can't add keyslot to plain device"); + FAIL_(crypt_keyslot_destroy(cd,1),"can't manipulate keyslots on plain device"); + EQ_(crypt_keyslot_status(cd, 0), CRYPT_SLOT_INVALID); + _remove_keyfiles(); crypt_free(cd); } @@ -703,9 +817,10 @@ static void CallbacksTest(void) }; size_t key_size = 256 / 8; - char *cipher = "aes"; - char *cipher_mode = "cbc-essiv:sha256"; - char *passphrase = PASSPHRASE; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; + const char *passphrase = PASSPHRASE; + char buf1[256] = {0}, buf2[256] = {0}; OK_(crypt_init(&cd, DEVICE_1)); crypt_set_log_callback(cd, &new_log, NULL); @@ -727,6 +842,22 @@ static void CallbacksTest(void) EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); OK_(crypt_deactivate(cd, CDEVICE_1)); + // Check error reporting. + // This must fail and create error message + crypt_deactivate(cd, CDEVICE_1); + + // Here context must be the same + crypt_get_error(buf1, sizeof(buf1)); + crypt_last_error(cd, buf2, sizeof(buf2)); + OK_(!*buf1); + OK_(!*buf2); + OK_(strcmp(buf1, buf2)); + + crypt_get_error(buf1, sizeof(buf1)); + crypt_last_error(cd, buf2, sizeof(buf2)); + OK_(*buf1); + OK_(*buf2); + crypt_free(cd); } @@ -750,7 +881,7 @@ static void UseLuksDevice(void) 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_(key_size, crypt_get_volume_key_size(cd)); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); EQ_(1032, crypt_get_data_offset(cd)); EQ_(0, crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, KEY1, strlen(KEY1))); @@ -804,17 +935,126 @@ static void AddDeviceLuks(void) struct crypt_params_luks1 params = { .hash = "sha512", .data_alignment = 2048, // 4M, data offset will be 4096 + .data_device = DEVICE_2 }; char key[128], key2[128]; - char *passphrase = "blabla"; - char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; + const char *passphrase = "blabla"; + const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; size_t key_size = strlen(mk_hex) / 2; - char *cipher = "aes"; - char *cipher_mode = "cbc-essiv:sha256"; + 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); + // init test devices + OK_(get_luks_offsets(1, key_size, 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_LUKS1, 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_LUKS1, 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_LUKS1, 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 = 4096; + OK_(get_luks_offsets(0, key_size, params.data_alignment, 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_LUKS1, 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_LUKS1, 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_LUKS1, 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_(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_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Context is already formated"); + FAIL_(crypt_format(cd, CRYPT_LUKS1, 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_LUKS1, 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_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Context is already formated"); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + 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_LUKS1, 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_LUKS1, 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); + EQ_(crypt_get_type(cd), NULL); + 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_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); @@ -863,7 +1103,7 @@ static void AddDeviceLuks(void) OK_(memcmp(key, key2, key_size)); OK_(strcmp(cipher, crypt_get_cipher(cd))); OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); - EQ_(key_size, crypt_get_volume_key_size(cd)); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); EQ_(4096, crypt_get_data_offset(cd)); OK_(strcmp(DEVICE_2, crypt_get_device_name(cd))); @@ -880,6 +1120,7 @@ static void AddDeviceLuks(void) FAIL_(crypt_deactivate(cd, CDEVICE_2), "not active"); crypt_free(cd); + _cleanup_dmdevices(); } static void UseTempVolumes(void) @@ -939,6 +1180,274 @@ static void UseTempVolumes(void) crypt_free(cd); } +static void LuksHeaderRestore(void) +{ + struct crypt_device *cd; + struct crypt_params_luks1 params = { + .hash = "sha512", + .data_alignment = 2048, // 4M, data offset will be 4096 + }; + struct crypt_params_plain pl_params = { + .hash = "sha1", + .skip = 0, + .offset = 0, + .size = 0 + }; + char key[128], key2[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; + + crypt_decode_key(key, mk_hex, key_size); + + OK_(get_luks_offsets(0, key_size, params.data_alignment, 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_HEADER), "Cannot restore header to PLAIN type device"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_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); + + // invalid headers + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_1), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_2), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_3), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_4), "Header too small"); + OK_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_HEADER)); + // wipe valid luks header + snprintf(cmd, sizeof(cmd), "dd if=/dev/zero of=" DMDIR L_DEVICE_OK " bs=512 count=%" PRIu64, r_payload_offset); + OK_(_system(cmd, 1)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_1), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_2), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_3), "Header corrupted"); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, EVL_HEADER_4), "Header too small"); + OK_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_HEADER)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); + + // volume key_size mismatch + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + memcpy(key2, key, key_size - 1); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key2, key_size - 1, ¶ms)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_HEADER), "Volume keysize mismatch"); + crypt_free(cd); + + // payload offset mismatch + params.data_alignment = 8192; + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + OK_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + FAIL_(crypt_header_restore(cd, CRYPT_LUKS1, VALID_HEADER), "Payload offset mismatch"); + //_system("dmsetup table;sleep 1",1); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void LuksHeaderLoad(void) +{ + struct crypt_device *cd; + struct crypt_params_luks1 params = { + .hash = "sha512", + .data_alignment = 2048, + }; + 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_luks_offsets(0, key_size, params.data_alignment, 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)); + snprintf(cmd, sizeof(cmd), "dd if=" EVL_HEADER_4 " of=" DMDIR H_DEVICE_WRONG " bs=512 count=%" PRIu64, r_payload_offset - 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_payload_offset + 1)); + // 0 sectors device for payload + OK_(create_dmdevice_over_loop(L_DEVICE_0S, r_payload_offset)); + + // 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_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + crypt_free(cd); + OK_(crypt_init(&cd, DMDIR H_DEVICE)); + OK_(crypt_load(cd, CRYPT_LUKS1, 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_LUKS1, NULL), "Device too small"); + EQ_(crypt_get_type(cd), NULL); + crypt_free(cd); + + // 0 secs for encrypted data area + params.data_alignment = 2048; + params.data_device = NULL; + OK_(crypt_init(&cd, DMDIR L_DEVICE_0S)); + OK_(crypt_format(cd, CRYPT_LUKS1, 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_LUKS1, 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_0S "bs=512 count=8", 1)); + OK_(crypt_init(&cd, DMDIR L_DEVICE_OK)); + FAIL_(crypt_load(cd, CRYPT_LUKS1, 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_LUKS1, NULL), "Can't load over nonLUKS device type"); + crypt_free(cd); + + _cleanup_dmdevices(); +} + +static void LuksHeaderBackup(void) +{ + struct crypt_device *cd; + struct crypt_params_luks1 params = { + .hash = "sha512", + .data_alignment = 2048, + }; + 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_luks_offsets(0, key_size, params.data_alignment, 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_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); + OK_(crypt_header_backup(cd, CRYPT_LUKS1, 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_LUKS1, BACKUP_FILE)); + OK_(crypt_load(cd, CRYPT_LUKS1, 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); + + _cleanup_dmdevices(); +} + +static void ResizeDeviceLuks(void) +{ + struct crypt_device *cd; + struct crypt_params_luks1 params = { + .hash = "sha512", + .data_alignment = 2048, + }; + 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_luks_offsets(0, key_size, params.data_alignment, 0, NULL, &r_payload_offset)); + OK_(get_luks_offsets(1, key_size, 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)); + OK_(crypt_format(cd, CRYPT_LUKS1, 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, 42)); + if (!device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(42, r_size >> SECTOR_SHIFT); + // autodetect encrypted device area size + OK_(crypt_resize(cd, CDEVICE_1, 0)); + if (!device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small"); + if (!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_LUKS1, 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 (!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 (!device_size(DMDIR CDEVICE_1, &r_size)) + EQ_(1000, r_size >> SECTOR_SHIFT); + FAIL_(crypt_resize(cd, CDEVICE_1, 1001), "Device too small"); + if (!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); + + _cleanup_dmdevices(); +} + static void HashDevicePlain(void) { struct crypt_device *cd; @@ -949,7 +1458,8 @@ static void HashDevicePlain(void) }; size_t key_size; - char *mk_hex, *keystr, key[256]; + const char *mk_hex, *keystr; + char key[256]; OK_(crypt_init(&cd, DEVICE_1)); OK_(crypt_format(cd, CRYPT_PLAIN, "aes", "cbc-essiv:sha256", NULL, NULL, 16, ¶ms)); @@ -991,17 +1501,20 @@ static void HashDevicePlain(void) OK_(strncmp(key, mk_hex, key_size)); OK_(crypt_deactivate(cd, CDEVICE_1)); + // Now without explicit limit OK_(crypt_activate_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0)); OK_(_get_key_dm(CDEVICE_1, key, sizeof(key))); FAIL_(strcmp(key, mk_hex), "only key length used"); OK_(strncmp(key, mk_hex, key_size)); OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); _remove_keyfiles(); // hash sha256 params.hash = "sha256"; + OK_(crypt_init(&cd, DEVICE_1)); OK_(crypt_format(cd, CRYPT_PLAIN, "aes", "cbc-essiv:sha256", NULL, NULL, 16, ¶ms)); // 0 1 2 3 4 5 6 7 8 9 a b c d e f @@ -1050,8 +1563,8 @@ static void NonFIPSAlg(void) struct crypt_params_luks1 params = {0}; char key[128] = ""; size_t key_size = 128; - char *cipher = "aes"; - char *cipher_mode = "cbc-essiv:sha256"; + const char *cipher = "aes"; + const char *cipher_mode = "cbc-essiv:sha256"; int ret; OK_(crypt_init(&cd, DEVICE_2)); @@ -1095,19 +1608,13 @@ int main (int argc, char *argv[]) crypt_set_debug_level(_debug ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE); RUN_(NonFIPSAlg, "Crypto is properly initialised in format"); //must be the first! -#if 0 - RUN_(LuksUUID, "luksUUID API call"); - RUN_(IsLuks, "isLuks API call"); - RUN_(LuksOpen, "luksOpen API call"); - RUN_(query_device, "crypt_query_device API call"); - RUN_(remove_device, "crypt_remove_device API call"); - RUN_(LuksFormat, "luksFormat API call"); - RUN_(LuksKeyGame, "luksAddKey, RemoveKey, KillSlot API calls"); - RUN_(DeviceResizeGame, "regular crypto, resize calls"); -#endif RUN_(AddDevicePlain, "plain device API creation exercise"); RUN_(HashDevicePlain, "plain device API hash test"); RUN_(AddDeviceLuks, "Format and use LUKS device"); + RUN_(LuksHeaderLoad, "test header load"); + RUN_(LuksHeaderRestore, "test LUKS header restore"); + RUN_(LuksHeaderBackup, "test LUKS header backup"); + RUN_(ResizeDeviceLuks, "Luks device resize tests"); RUN_(UseLuksDevice, "Use pre-formated LUKS device"); RUN_(SuspendDevice, "Suspend/Resume test"); RUN_(UseTempVolumes, "Format and use temporary encrypted device");