bitlk: Fix parsing startup key metadata

This fixes multiple issues found by coverity in the startup key
code and also makes the parsing less complicated -- we don't need
to loop through all metadata entries in the BEK file if we are
expecting only one metadata entry of a specific type.
This commit is contained in:
Vojtech Trefny
2021-02-04 14:49:54 +01:00
parent d1ffca3189
commit 3cd158b983

View File

@@ -904,6 +904,7 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
*vk = crypt_alloc_volume_key(key_size, key);
if (*vk == NULL)
return -ENOMEM;
return 0;
/* optional "ExternalKey" string, we can safely ignore it */
} else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
;
@@ -915,7 +916,8 @@ static int parse_external_key_entry(struct crypt_device *cd, const char *data, i
start += key_entry_size;
}
return 0;
/* if we got here we failed to parse the metadata */
return -EINVAL;
}
/* check if given passphrase can be a startup key (has right format) and convert it */
@@ -931,12 +933,9 @@ static int get_startup_key(struct crypt_device *cd,
uint16_t key_entry_size = 0;
uint16_t key_entry_type = 0;
uint16_t key_entry_value = 0;
int start = 0;
int end = 0;
int r = 0;
if (passwordLen < BITLK_BEK_FILE_HEADER_LEN)
return 0;
return -EPERM;
memcpy(&bek_header, password, BITLK_BEK_FILE_HEADER_LEN);
@@ -945,7 +944,7 @@ static int get_startup_key(struct crypt_device *cd,
if (strcmp(guid_buf, vmk->guid) == 0)
log_dbg(cd, "Found matching startup key for VMK %s", vmk->guid);
else
return 0;
return -EPERM;
if (bek_header.metadata_version != 1) {
log_err(cd, "Unsupported BEK metadata version %" PRIu32 "", bek_header.metadata_version);
@@ -957,44 +956,31 @@ static int get_startup_key(struct crypt_device *cd,
return -EINVAL;
}
start = BITLK_BEK_FILE_HEADER_LEN;
end = bek_header.metadata_size;
while (end - start > 2) {
/* size of this entry */
memcpy(&key_entry_size, password + start, sizeof(key_entry_size));
key_entry_size = le16_to_cpu(key_entry_size);
if (key_entry_size < BITLK_ENTRY_HEADER_LEN) {
log_dbg(cd, "Unexpected metadata entry size %" PRIu16 " when parsing BEK file", key_entry_size);
break;
}
/* type and value of this entry */
memcpy(&key_entry_type, password + start + sizeof(key_entry_size), sizeof(key_entry_type));
memcpy(&key_entry_value,
password + start + sizeof(key_entry_size) + sizeof(key_entry_type),
sizeof(key_entry_value));
key_entry_type = le16_to_cpu(key_entry_type);
key_entry_value = le16_to_cpu(key_entry_value);
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
r = parse_external_key_entry(cd, password,
start + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
end, su_key);
if (r < 0)
return r;
} else {
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
return -EINVAL;
}
start += key_entry_size;
/* we are expecting exactly one metadata entry starting immediately after the header */
memcpy(&key_entry_size, password + BITLK_BEK_FILE_HEADER_LEN, sizeof(key_entry_size));
key_entry_size = le16_to_cpu(key_entry_size);
if (key_entry_size < BITLK_ENTRY_HEADER_LEN) {
log_dbg(cd, "Unexpected metadata entry size %" PRIu16 " when parsing BEK file", key_entry_size);
return -EINVAL;
}
if (*su_key == NULL)
log_dbg(cd, "Failed to get VMK from matching BEK key file.");
/* type and value of this entry */
memcpy(&key_entry_type, password + BITLK_BEK_FILE_HEADER_LEN + sizeof(key_entry_size), sizeof(key_entry_type));
memcpy(&key_entry_value,
password + BITLK_BEK_FILE_HEADER_LEN + sizeof(key_entry_size) + sizeof(key_entry_type),
sizeof(key_entry_value));
key_entry_type = le16_to_cpu(key_entry_type);
key_entry_value = le16_to_cpu(key_entry_value);
return 0;
if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
return parse_external_key_entry(cd, password,
BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
passwordLen, su_key);
} else {
log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
return -EINVAL;
}
}
static int bitlk_kdf(struct crypt_device *cd,
@@ -1161,12 +1147,6 @@ int BITLK_get_volume_key(struct crypt_device *cd,
next_vmk = next_vmk->next;
continue;
}
if (vmk_dec_key == NULL){
/* r = 0 but no key -> given passphrase is not a recovery startup key */
r = -EPERM;
next_vmk = next_vmk->next;
continue;
}
log_dbg(cd, "Trying to use external key found in provided password.");
} else {
/* only passphrase, recovery passphrase and startup key VMKs supported right now */