* Allow to activate by internally cached volume key
authorMilan Broz <gmazyland@gmail.com>
Sun, 14 Nov 2010 17:22:04 +0000 (17:22 +0000)
committerMilan Broz <gmazyland@gmail.com>
Sun, 14 Nov 2010 17:22:04 +0000 (17:22 +0000)
  (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

ChangeLog
lib/libcryptsetup.h
lib/setup.c
tests/api-test.c

index 8d34a04..1997bc6 100644 (file)
--- 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  <mbroz@redhat.com>
        * No longer support luksDelKey, reload and --non-exclusive.
index 78e0c89..937a384 100644 (file)
@@ -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,
index cd8957b..9519e99 100644 (file)
@@ -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,
index 25170aa..b23a12f 100644 (file)
@@ -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");