From: Milan Broz Date: Sun, 14 Nov 2010 17:22:04 +0000 (+0000) Subject: * Allow to activate by internally cached volume key X-Git-Tag: upstream/1.6~566 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=312d8eca7342fb7de37f9124fb73119018a94523;p=platform%2Fupstream%2Fcryptsetup.git * Allow to activate by internally cached volume key (format/activate without keyslots active - used for temporary devices). * Initialize volume key from active device in crypt_init_by_name() git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@365 36d66b0a-2a48-0410-832c-cd162a569da5 --- diff --git a/ChangeLog b/ChangeLog index 8d34a04..1997bc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ * Fix password callback call. * Fix default plain password entry from terminal in activate_by_passphrase. * Add --dump-master-key option for luksDump to allow volume key dump. + * Allow to activate by internally cached volume key + (format/activate without keyslots active - used for temporary devices). + * Initialize volume key from active device in crypt_init_by_name() 2010-11-01 Milan Broz * No longer support luksDelKey, reload and --non-exclusive. diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 78e0c89..937a384 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -175,7 +175,7 @@ struct crypt_params_luks1 { * @cipher_mode - including IV specification (e.g. "xts-plain") * @uuid - requested UUID or NULL if it should be generated * @volume_key - pre-generated volume key or NULL if it should be generated (only for LUKS) - * @volume_key_size - size og volume key in bytes. + * @volume_key_size - size of volume key in bytes. * @params - crypt type specific parameters * * Note that crypt_format do not enable any keyslot, but it stores volume key internally @@ -439,9 +439,12 @@ int crypt_activate_by_keyfile(struct crypt_device *cd, * * @cd - crypt device handle * @name - name of device to create, if NULL only check volume key - * @volume_key - provided volume key + * @volume_key - provided volume key (or NULL to use internal) * @volume_key_size - size of @volume_key * @flags - activation flags + * + * If NULL is used for volume_key, device has to be initialized + * by previous operation (like crypt_format() or crypt_init_by_name()) */ int crypt_activate_by_volume_key(struct crypt_device *cd, const char *name, diff --git a/lib/setup.c b/lib/setup.c index cd8957b..9519e99 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -482,8 +482,7 @@ static int volume_key_by_terminal_passphrase(struct crypt_device *cd, int keyslo *vk = NULL; do { - if (*vk) - crypt_free_volume_key(*vk); + crypt_free_volume_key(*vk); *vk = NULL; r = key_from_terminal(cd, NULL, &passphrase_read, @@ -1019,6 +1018,7 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name) struct crypt_active_device cad; char *device = NULL, *cipher_full = NULL, *device_uuid = NULL; char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; + char *key = NULL; int key_size = 0, r; @@ -1034,28 +1034,34 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name) } r = dm_query_device(name, &device, &cad.size, &cad.iv_offset, &cad.offset, - &cipher_full, &key_size, NULL, NULL, NULL, + &cipher_full, &key_size, &key, NULL, NULL, &device_uuid); + if (r < 0) + goto out; /* Underlying device disappeared but mapping still active */ - if (r >= 0 && !device) + if (!device) log_verbose(NULL, _("Underlying device for crypt device %s disappeared.\n"), name); - if (r >= 0) - r = crypt_init(cd, device); + *cd = NULL; + r = crypt_init(cd, device); + if (r < 0) + goto out; /* Try to initialise basic parameters from active device */ - if (!r && *device_uuid) { + if (device_uuid) { if (!strncmp(CRYPT_PLAIN, device_uuid, sizeof(CRYPT_PLAIN)-1)) { (*cd)->type = strdup(CRYPT_PLAIN); (*cd)->plain_uuid = strdup(device_uuid); (*cd)->plain_hdr.hash = NULL; /* no way to get this */ (*cd)->plain_hdr.offset = cad.offset; (*cd)->plain_hdr.skip = cad.iv_offset; - (*cd)->volume_key = crypt_alloc_volume_key(key_size, NULL); - if (!(*cd)->volume_key) + (*cd)->volume_key = crypt_alloc_volume_key(key_size, key); + if (!(*cd)->volume_key) { r = -ENOMEM; + goto out; + } r = crypt_parse_name_and_mode(cipher_full, cipher, cipher_mode); if (!r) { @@ -1063,11 +1069,29 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name) (*cd)->plain_cipher_mode = strdup(cipher_mode); } } else if (!strncmp(CRYPT_LUKS1, device_uuid, sizeof(CRYPT_LUKS1)-1)) { - if (device) - r = crypt_load(*cd, CRYPT_LUKS1, NULL); + if (device) { + if (crypt_load(*cd, CRYPT_LUKS1, NULL) < 0 || + crypt_volume_key_verify(*cd, key, key_size) < 0) { + log_dbg("LUKS device header does not match active device."); + goto out; + } + + (*cd)->volume_key = crypt_alloc_volume_key(key_size, key); + if (!(*cd)->volume_key) { + r = -ENOMEM; + goto out; + } + } } - } + } else + log_dbg("Active device has no UUID set, some parameters are not set."); +out: + if (r < 0) { + crypt_free(*cd); + *cd = NULL; + } + crypt_safe_free(key); free(device); free(cipher_full); free(device_uuid); @@ -1363,8 +1387,7 @@ void crypt_free(struct crypt_device *cd) log_dbg("Releasing crypt device %s context.", cd->device); dm_exit(); - if (cd->volume_key) - crypt_free_volume_key(cd->volume_key); + crypt_free_volume_key(cd->volume_key); free(cd->device); free(cd->type); @@ -1874,18 +1897,22 @@ int crypt_activate_by_volume_key(struct crypt_device *cd, log_dbg("Activating volume %s by volume key.", name); - if (!volume_key_size) - return -EINVAL; - /* use key directly, no hash */ - if (isPLAIN(cd->type)) + if (isPLAIN(cd->type)) { + if (!volume_key || !volume_key_size || !cd->volume_key || + volume_key_size != cd->volume_key->keylength) { + log_err(cd, _("Incorrect volume key specified for plain device.\n")); + return -EINVAL; + } + return create_device_helper(cd, name, NULL, cd->plain_cipher, cd->plain_cipher_mode, NULL, volume_key, volume_key_size, cd->volume_key->keylength, 0, cd->plain_hdr.skip, cd->plain_hdr.offset, cd->plain_uuid, flags & CRYPT_ACTIVATE_READONLY, 0, 0); + } if (!isLUKS(cd->type)) { - log_err(cd, _("This operation is supported only for LUKS device.\n")); + log_err(cd, _("Device type is not properly initialised.\n")); return -EINVAL; } @@ -1899,6 +1926,16 @@ int crypt_activate_by_volume_key(struct crypt_device *cd, } } + /* If key is not provided, try to use internal key */ + if (!volume_key) { + if (!cd->volume_key) { + log_err(cd, _("Volume key does not match the volume.\n")); + return -EINVAL; + } + volume_key_size = cd->volume_key->keylength; + volume_key = cd->volume_key->key; + } + vk = crypt_alloc_volume_key(volume_key_size, volume_key); if (!vk) return -ENOMEM; @@ -1950,7 +1987,6 @@ int crypt_deactivate(struct crypt_device *cd, const char *name) return r; } -// misc helper functions int crypt_volume_key_get(struct crypt_device *cd, int keyslot, char *volume_key, diff --git a/tests/api-test.c b/tests/api-test.c index 25170aa..b23a12f 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -811,6 +811,68 @@ static void AddDeviceLuks(void) crypt_free(cd); } +static void UseTempVolumes(void) +{ + struct crypt_device *cd; + struct crypt_params_plain params = { + .hash = "sha1", + .skip = 0, + .offset = 0, + }; + + // 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_LUKS1, "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); + + // Volume key is properly initialised from active device + OK_(crypt_init_by_name(&cd, CDEVICE_2)); + OK_(crypt_deactivate(cd, CDEVICE_2)); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0)); + 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 + system("dmsetup create " CDEVICE_2 " --table \"" + "0 100 crypt aes-cbc-essiv:sha256 deadbabedeadbabedeadbabedeadbabe 0 " + DEVICE_2 " 2048\""); + 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) + system("dmsetup create " CDEVICE_2 " --table \"" + "0 100 crypt aes-cbc-essiv:sha256 deadbabedeadbabedeadbabedeadbabe 0 " + DEVICE_2 " 2048\" " + "-u CRYPT-LUKS1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-ctest1"); + 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_LUKS1, NULL)); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, NULL, 0, 0), "volume key is lost"); + crypt_free(cd); + + // Plain device + OK_(crypt_init(&cd, DEVICE_2)); + OK_(crypt_format(cd, CRYPT_PLAIN, "aes", "cbc-essiv:sha256", NULL, NULL, 16, NULL)); + FAIL_(crypt_activate_by_volume_key(cd, NULL, "xxx", 3, 0), "cannot verify key with plain"); + FAIL_(crypt_volume_key_verify(cd, "xxx", 3), "cannot verify key with plain"); + FAIL_(crypt_activate_by_volume_key(cd, CDEVICE_2, "xxx", 3, 0), "wrong key lenght"); + OK_(crypt_activate_by_volume_key(cd, CDEVICE_2, "volumekeyvolumek", 16, 0)); + EQ_(crypt_status(cd, CDEVICE_2), CRYPT_ACTIVE); + OK_(crypt_deactivate(cd, CDEVICE_2)); + crypt_free(cd); +} + // Check that gcrypt is properly initialised in format static void NonFIPSAlg(void) { @@ -892,6 +954,7 @@ int main (int argc, char *argv[]) RUN_(AddDeviceLuks, "Format and use LUKS device"); RUN_(UseLuksDevice, "Use pre-formated LUKS device"); RUN_(SuspendDevice, "Suspend/Resume test"); + RUN_(UseTempVolumes, "Format and use temporary encrypted device"); RUN_(CallbacksTest, "API callbacks test");