Commit 08e7c143 authored by Ondrej Kozina's avatar Ondrej Kozina Committed by Milan Broz

Add internal code for LUKS2 keyslot params.

This fixes crypt_keyslot_add_by_key where we were unable to store
keyslot (unbound to segment) with different key_size.
The code used (new) volume key size implicitly which could be wrong
if new size was not compatible with cipher parameter for keyslot area.
parent d399dfa7
......@@ -95,6 +95,25 @@ struct luks2_hdr {
json_object *jobj;
};
struct luks2_keyslot_params {
enum { LUKS2_KEYSLOT_AF_LUKS1 = 0 } af_type;
enum { LUKS2_KEYSLOT_AREA_RAW = 0 } area_type;
union {
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
unsigned int stripes;
} luks1;
} af;
union {
struct {
char encryption[65]; // or include utils_crypt.h
size_t key_size;
} raw;
} area;
};
/*
* Supportable header sizes (hdr_disk + JSON area)
* Also used as offset for the 2nd header.
......@@ -151,7 +170,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
const struct volume_key *vk);
const struct volume_key *vk,
const struct luks2_keyslot_params *params);
int LUKS2_keyslot_wipe(struct crypt_device *cd,
struct luks2_hdr *hdr,
......@@ -299,6 +319,10 @@ uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params);
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot,
struct luks2_keyslot_params *params);
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment);
int LUKS2_get_keyslot_key_size(struct luks2_hdr *hdr, int keyslot);
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr, const char *type);
......
......@@ -83,7 +83,8 @@ struct json_object *LUKS2_array_remove(struct json_object *array, const char *nu
* LUKS2 keyslots handlers (EXPERIMENTAL)
*/
typedef int (*keyslot_alloc_func)(struct crypt_device *cd, int keyslot,
size_t volume_key_len);
size_t volume_key_len,
const struct luks2_keyslot_params *params);
typedef int (*keyslot_open_func) (struct crypt_device *cd, int keyslot,
const char *password, size_t password_len,
char *volume_key, size_t volume_key_len);
......@@ -96,7 +97,8 @@ typedef int (*keyslot_validate_func) (struct crypt_device *cd, int keyslot);
int luks2_keyslot_alloc(struct crypt_device *cd,
int keyslot,
size_t volume_key_len);
size_t volume_key_len,
const struct luks2_keyslot_params *params);
typedef struct {
const char *name;
......
......@@ -26,6 +26,8 @@
#include <ctype.h>
#include <uuid/uuid.h>
#define LUKS_STRIPES 4000
struct interval {
uint64_t offset;
uint64_t length;
......@@ -1611,6 +1613,78 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
return json_object_get_string(jobj3);
}
static int luks2_keyslot_af_params(json_object *jobj_af, struct luks2_keyslot_params *params)
{
int r;
json_object *jobj_type, *jobj1;
/* currently we only support luks1 AF */
json_object_object_get_ex(jobj_af, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "luks1"))
return 1;
/* process luks1 af params */
json_object_object_get_ex(jobj_af, "stripes", &jobj1);
params->af.luks1.stripes = json_object_get_int(jobj1);
if (params->af.luks1.stripes != LUKS_STRIPES)
return 1;
json_object_object_get_ex(jobj_af, "hash", &jobj1);
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return 1;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
return 0;
}
static int luks2_keyslot_area_params(json_object *jobj_area, struct luks2_keyslot_params *params)
{
int r;
json_object *jobj_type, *jobj1;
/* currently we only support raw length preserving area encryption */
json_object_object_get_ex(jobj_area, "type", &jobj_type);
if (strcmp(json_object_get_string(jobj_type), "raw"))
return 1;
/* process raw area encryption params */
json_object_object_get_ex(jobj_area, "encryption", &jobj1);
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption), "%s",
json_object_get_string(jobj1));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return 1;
json_object_object_get_ex(jobj_area, "key_size", &jobj1);
params->area.raw.key_size = json_object_get_int(jobj1);
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
return 0;
}
/* keyslot must be validated */
int LUKS2_get_keyslot_params(struct luks2_hdr *hdr, int keyslot, struct luks2_keyslot_params *params)
{
json_object *jobj_keyslot, *jobj_af, *jobj_area;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
if (!jobj_keyslot)
return -ENOENT;
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af))
return -EINVAL;
if (luks2_keyslot_af_params(jobj_af, params))
return -EINVAL;
if (luks2_keyslot_area_params(jobj_area, params))
return -EINVAL;
return 0;
}
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
{
json_object *jobj1, *jobj2, *jobj3, *jobj4;
......
......@@ -117,6 +117,50 @@ int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment)
return num;
}
int LUKS2_keyslot_params_default(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t key_size, struct luks2_keyslot_params *params)
{
int r, integrity_key_size = crypt_get_integrity_key_size(cd);
const struct crypt_pbkdf_type *pbkdf = crypt_get_pbkdf_type(cd);
if (!hdr || !pbkdf || !params)
return -EINVAL;
params->af_type = LUKS2_KEYSLOT_AF_LUKS1;
params->area_type = LUKS2_KEYSLOT_AREA_RAW;
/* set keyslot AF parameters */
/* currently we use hash for AF from pbkdf settings */
r = snprintf(params->af.luks1.hash, sizeof(params->af.luks1.hash),
"%s", pbkdf->hash);
if (r < 0 || (size_t)r >= sizeof(params->af.luks1.hash))
return -EINVAL;
params->af.luks1.stripes = 4000;
/* set keyslot area encryption parameters */
/* short circuit authenticated encryption hardcoded defaults */
if (crypt_get_integrity_tag_size(cd) || key_size == 0) {
// FIXME: fixed cipher and key size can be wrong
snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"aes-xts-plain64");
params->area.raw.key_size = 32;
return 0;
}
r = snprintf(params->area.raw.encryption, sizeof(params->area.raw.encryption),
"%s", LUKS2_get_cipher(hdr, CRYPT_DEFAULT_SEGMENT));
if (r < 0 || (size_t)r >= sizeof(params->area.raw.encryption))
return -EINVAL;
/* Slot encryption tries to use the same key size as for the main algorithm */
if (integrity_key_size > key_size)
return -EINVAL;
params->area.raw.key_size = key_size - integrity_key_size;
return 0;
}
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot)
{
crypt_keyslot_info ki;
......@@ -281,7 +325,8 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
const struct volume_key *vk)
const struct volume_key *vk,
const struct luks2_keyslot_params *params)
{
const keyslot_handler *h;
int r;
......@@ -295,7 +340,7 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
if (!h)
return -EINVAL;
r = h->alloc(cd, keyslot, vk->keylength);
r = h->alloc(cd, keyslot, vk->keylength, params);
if (r)
return r;
} else if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
......
......@@ -376,18 +376,24 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
int luks2_keyslot_alloc(struct crypt_device *cd,
int keyslot,
size_t volume_key_len)
size_t volume_key_len,
const struct luks2_keyslot_params *params)
{
struct luks2_hdr *hdr;
const struct crypt_pbkdf_type *pbkdf;
char cipher[2 * MAX_CIPHER_LEN + 1], num[16];
char num[16];
uint64_t area_offset, area_length;
json_object *jobj_keyslots, *jobj_keyslot, *jobj_kdf, *jobj_af, *jobj_area;
size_t keyslot_key_len;
int r;
log_dbg("Trying to allocate LUKS2 keyslot %d.", keyslot);
if (!params || params->area_type != LUKS2_KEYSLOT_AREA_RAW ||
params->af_type != LUKS2_KEYSLOT_AF_LUKS1) {
log_dbg("Invalid LUKS2 keyslot parameters.");
return -EINVAL;
}
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
......@@ -439,28 +445,15 @@ int luks2_keyslot_alloc(struct crypt_device *cd,
/* AF object */
jobj_af = json_object_new_object();
json_object_object_add(jobj_af, "type", json_object_new_string("luks1"));
json_object_object_add(jobj_af, "hash", json_object_new_string(pbkdf->hash));
json_object_object_add(jobj_af, "stripes", json_object_new_int(4000));
json_object_object_add(jobj_af, "hash", json_object_new_string(params->af.luks1.hash));
json_object_object_add(jobj_af, "stripes", json_object_new_int(params->af.luks1.stripes));
json_object_object_add(jobj_keyslot, "af", jobj_af);
/* Area object */
jobj_area = json_object_new_object();
json_object_object_add(jobj_area, "type", json_object_new_string("raw"));
/* Slot encryption tries to use the same key size as fot the main algorithm */
keyslot_key_len = volume_key_len - crypt_get_integrity_key_size(cd);
/* Cannot use metadata tags in keyslot */
if (crypt_get_integrity_tag_size(cd)) {
snprintf(cipher, sizeof(cipher), "aes-xts-plain64"); // FIXME: fixed cipher and key size can be wrong
keyslot_key_len = 32;
} else if (crypt_get_cipher_mode(cd))
snprintf(cipher, sizeof(cipher), "%s-%s", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
else
snprintf(cipher, sizeof(cipher), "%s", crypt_get_cipher(cd));
json_object_object_add(jobj_area, "encryption", json_object_new_string(cipher));
json_object_object_add(jobj_area, "key_size", json_object_new_int(keyslot_key_len));
json_object_object_add(jobj_area, "encryption", json_object_new_string(params->area.raw.encryption));
json_object_object_add(jobj_area, "key_size", json_object_new_int(params->area.raw.key_size));
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
json_object_object_add(jobj_keyslot, "area", jobj_area);
......
......@@ -611,6 +611,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
int i, r, last_active = 0;
uint64_t offset, area_length;
char buf[256], luksMagic[] = LUKS_MAGIC;
struct luks2_keyslot_params params;
jobj_digest = LUKS2_get_digest_jobj(hdr2, 0);
if (!jobj_digest)
......@@ -628,10 +629,17 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
return -EINVAL;
}
key_size = r = LUKS2_get_volume_key_size(hdr2, 0);
/* We really do not care about params later except keys_size */
r = LUKS2_keyslot_params_default(cd, hdr2, 0, &params);
if (r < 0)
return -EINVAL;
r = LUKS2_get_volume_key_size(hdr2, 0);
if (r < 0)
return -EINVAL;
key_size = r;
params.area.raw.key_size = key_size;
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
if (LUKS2_keyslot_info(hdr2, i) == CRYPT_SLOT_INACTIVE)
continue;
......@@ -670,7 +678,7 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd, struct luks2_hdr *hdr2, struct
if (LUKS2_find_area_gap(cd, hdr2, key_size, &offset, &area_length))
return -EINVAL;
/* FIXME: luks2 reload is required! */
if (luks2_keyslot_alloc(cd, i, key_size))
if (luks2_keyslot_alloc(cd, i, key_size, &params))
return -EINVAL;
}
......
......@@ -2563,6 +2563,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
size_t new_passphrase_size)
{
int digest, r, active_slots;
struct luks2_keyslot_params params;
struct volume_key *vk = NULL;
log_dbg("Adding new keyslot, existing passphrase %sprovided,"
......@@ -2614,13 +2615,16 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
digest = r;
if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0);
if (r >= 0)
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
CONST_CAST(char*)new_passphrase,
new_passphrase_size, vk);
new_passphrase_size, vk, &params);
}
if (r < 0)
......@@ -2645,6 +2649,7 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
size_t new_passphrase_size)
{
int digest, r;
struct luks2_keyslot_params params;
struct volume_key *vk = NULL;
if (!passphrase || !new_passphrase)
......@@ -2696,6 +2701,9 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size,
&cd->u.luks1.hdr, vk, cd);
} else if (isLUKS2(cd->type)) {
r = LUKS2_get_keyslot_params(&cd->u.luks2.hdr, keyslot_old, &params);
if (r)
goto out;
if (keyslot_old != keyslot_new) {
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot_new, digest, 1, 0);
if (r < 0)
......@@ -2713,7 +2721,7 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr,
keyslot_new, new_passphrase,
new_passphrase_size, vk);
new_passphrase_size, vk, &params);
} else
r = -EINVAL;
......@@ -2748,6 +2756,7 @@ int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd,
{
int digest, r, active_slots;
size_t passwordLen, new_passwordLen;
struct luks2_keyslot_params params;
char *password = NULL, *new_password = NULL;
struct volume_key *vk = NULL;
......@@ -2807,12 +2816,15 @@ int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd,
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
digest = r;
if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0);
if (r >= 0)
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
new_password, new_passwordLen, vk);
new_password, new_passwordLen, vk, &params);
}
out:
crypt_safe_free(password);
......@@ -4385,6 +4397,7 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
uint32_t flags)
{
int digest, r;
struct luks2_keyslot_params params;
struct volume_key *vk = NULL;
if (!passphrase)
......@@ -4411,13 +4424,20 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
return -ENOMEM;
/* no segment means we're going to store key without assigned segment (unused in dm-crypt) */
if (flags & CRYPT_VOLUME_KEY_NO_SEGMENT)
if (flags & CRYPT_VOLUME_KEY_NO_SEGMENT) {
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
else
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, 0, &params);
} else {
digest = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylength, &params);
}
r = digest;
if (r < 0) {
log_err(cd, _("Failed to initialise default LUKS2 keyslot parameters.\n"));
goto out;
}
r = digest;
if (r < 0) {
log_err(cd, _("Volume key does not match the volume.\n"));
goto out;
......@@ -4429,8 +4449,8 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
goto out;
}
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
passphrase, passphrase_size, vk);
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
passphrase, passphrase_size, vk, &params);
out:
crypt_free_volume_key(vk);
if (r < 0) {
......
......@@ -2262,6 +2262,11 @@ static void Luks2KeyslotAdd(void)
/* 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);
/* in general crypt_keyslot_add_by_key must allow any reasonable key size
* even though such keyslot will not be usable for segment encryption */
EQ_(crypt_keyslot_add_by_key(cd, 2, key2, key_size-1, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 2);
EQ_(crypt_keyslot_add_by_key(cd, 3, key2, 13, PASSPHRASE1, strlen(PASSPHRASE1), CRYPT_VOLUME_KEY_NO_SEGMENT), 3);
crypt_free(cd);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment