* 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.
* @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
*
* @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,
*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,
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;
}
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) {
(*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);
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);
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;
}
}
}
+ /* 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;
return r;
}
-// misc helper functions
int crypt_volume_key_get(struct crypt_device *cd,
int keyslot,
char *volume_key,
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)
{
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");