Add empty string check to LUKS2 JSON validation.

Most of the LUKS2 fields cannot be empty,
add check for JSON validation for it to fail early.

Fixes: #746
This commit is contained in:
Milan Broz
2022-06-08 14:35:23 +02:00
parent f97af5dcfe
commit ba9e36ceae
6 changed files with 88 additions and 32 deletions

View File

@@ -75,6 +75,8 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
json_bool validate_json_uint32(json_object *jobj);
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
const char *section, const char *key, json_type type);
json_object *json_contains_string(struct crypt_device *cd, json_object *jobj,
const char *name, const char *section, const char *key);
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size);
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr);

View File

@@ -292,6 +292,20 @@ json_object *json_contains(struct crypt_device *cd, json_object *jobj, const cha
return sobj;
}
json_object *json_contains_string(struct crypt_device *cd, json_object *jobj,
const char *name, const char *section, const char *key)
{
json_object *sobj = json_contains(cd, jobj, name, section, key, json_type_string);
if (!sobj)
return NULL;
if (strlen(json_object_get_string(sobj)) < 1)
return NULL;
return sobj;
}
json_bool validate_json_uint32(json_object *jobj)
{
int64_t tmp;
@@ -406,7 +420,7 @@ static int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_keys
{
json_object *jobj_key_size;
if (!json_contains(cd, hdr_keyslot, key, "Keyslot", "type", json_type_string))
if (!json_contains_string(cd, hdr_keyslot, key, "Keyslot", "type"))
return 1;
if (!(jobj_key_size = json_contains(cd, hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
return 1;
@@ -430,7 +444,7 @@ int LUKS2_token_validate(struct crypt_device *cd,
if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
return 1;
if (!json_contains(cd, jobj_token, key, "Token", "type", json_type_string))
if (!json_contains_string(cd, jobj_token, key, "Token", "type"))
return 1;
jarr = json_contains(cd, jobj_token, key, "Token", "keyslots", json_type_array);
@@ -518,17 +532,17 @@ static int hdr_validate_crypt_segment(struct crypt_device *cd, json_object *jobj
uint32_t sector_size;
uint64_t ivoffset;
if (!(jobj_ivoffset = json_contains(cd, jobj, key, "Segment", "iv_tweak", json_type_string)) ||
!json_contains(cd, jobj, key, "Segment", "encryption", json_type_string) ||
if (!(jobj_ivoffset = json_contains_string(cd, jobj, key, "Segment", "iv_tweak")) ||
!json_contains_string(cd, jobj, key, "Segment", "encryption") ||
!(jobj_sector_size = json_contains(cd, jobj, key, "Segment", "sector_size", json_type_int)))
return 1;
/* integrity */
if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
if (!json_contains(cd, jobj, key, "Segment", "integrity", json_type_object) ||
!json_contains(cd, jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
!json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
!json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "type") ||
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_encryption") ||
!json_contains_string(cd, jobj_integrity, key, "Segment integrity", "journal_integrity"))
return 1;
}
@@ -689,9 +703,9 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
return 1;
/* those fields are mandatory for all segment types */
if (!(jobj_type = json_contains(cd, val, key, "Segment", "type", json_type_string)) ||
!(jobj_offset = json_contains(cd, val, key, "Segment", "offset", json_type_string)) ||
!(jobj_size = json_contains(cd, val, key, "Segment", "size", json_type_string)))
if (!(jobj_type = json_contains_string(cd, val, key, "Segment", "type")) ||
!(jobj_offset = json_contains_string(cd, val, key, "Segment", "offset")) ||
!(jobj_size = json_contains_string(cd, val, key, "Segment", "size")))
return 1;
if (!numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
@@ -845,9 +859,9 @@ static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
json_object_object_foreach(jobj_keyslots, key, val) {
if (!(jobj_area = json_contains(cd, val, key, "Keyslot", "area", json_type_object)) ||
!json_contains(cd, jobj_area, key, "Keyslot area", "type", json_type_string) ||
!(jobj_offset = json_contains(cd, jobj_area, key, "Keyslot", "offset", json_type_string)) ||
!(jobj_length = json_contains(cd, jobj_area, key, "Keyslot", "size", json_type_string)) ||
!json_contains_string(cd, jobj_area, key, "Keyslot area", "type") ||
!(jobj_offset = json_contains_string(cd, jobj_area, key, "Keyslot", "offset")) ||
!(jobj_length = json_contains_string(cd, jobj_area, key, "Keyslot", "size")) ||
!numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
!numbered(cd, "size", json_object_get_string(jobj_length))) {
free(intervals);
@@ -895,7 +909,7 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
if (!numbered(cd, "Digest", key))
return 1;
if (!json_contains(cd, val, key, "Digest", "type", json_type_string) ||
if (!json_contains_string(cd, val, key, "Digest", "type") ||
!(jarr_keys = json_contains(cd, val, key, "Digest", "keyslots", json_type_array)) ||
!(jarr_segs = json_contains(cd, val, key, "Digest", "segments", json_type_array)))
return 1;
@@ -919,7 +933,7 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
if (!(jobj_config = json_contains(cd, hdr_jobj, "", "JSON area", "config", json_type_object)))
return 1;
if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "json_size", json_type_string)) ||
if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "json_size")) ||
!json_str_to_uint64(jobj, &metadata_size))
return 1;
@@ -927,7 +941,7 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
* binary header size */
metadata_size += LUKS2_HDR_BIN_LEN;
if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "keyslots_size", json_type_string)) ||
if (!(jobj = json_contains_string(cd, jobj_config, "section", "Config", "keyslots_size")) ||
!json_str_to_uint64(jobj, &keyslots_size))
return 1;

View File

@@ -680,49 +680,49 @@ static int luks2_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
count = json_object_object_length(jobj_kdf);
jobj1 = json_contains(cd, jobj_kdf, "", "kdf section", "type", json_type_string);
jobj1 = json_contains_string(cd, jobj_kdf, "", "kdf section", "type");
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, CRYPT_KDF_PBKDF2)) {
if (count != 4 || /* type, salt, hash, iterations only */
!json_contains(cd, jobj_kdf, "kdf type", type, "hash", json_type_string) ||
!json_contains_string(cd, jobj_kdf, "kdf type", type, "hash") ||
!json_contains(cd, jobj_kdf, "kdf type", type, "iterations", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
return -EINVAL;
} else if (!strcmp(type, CRYPT_KDF_ARGON2I) || !strcmp(type, CRYPT_KDF_ARGON2ID)) {
if (count != 5 || /* type, salt, time, memory, cpus only */
!json_contains(cd, jobj_kdf, "kdf type", type, "time", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "memory", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "cpus", json_type_int) ||
!json_contains(cd, jobj_kdf, "kdf type", type, "salt", json_type_string))
!json_contains_string(cd, jobj_kdf, "kdf type", type, "salt"))
return -EINVAL;
}
jobj1 = json_contains(cd, jobj_af, "", "af section", "type", json_type_string);
jobj1 = json_contains_string(cd, jobj_af, "", "af section", "type");
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, "luks1")) {
if (!json_contains(cd, jobj_af, "", "luks1 af", "hash", json_type_string) ||
if (!json_contains_string(cd, jobj_af, "", "luks1 af", "hash") ||
!json_contains(cd, jobj_af, "", "luks1 af", "stripes", json_type_int))
return -EINVAL;
} else
return -EINVAL;
// FIXME check numbered
jobj1 = json_contains(cd, jobj_area, "", "area section", "type", json_type_string);
jobj1 = json_contains_string(cd, jobj_area, "", "area section", "type");
if (!jobj1)
return -EINVAL;
type = json_object_get_string(jobj1);
if (!strcmp(type, "raw")) {
if (!json_contains(cd, jobj_area, "area", "raw type", "encryption", json_type_string) ||
if (!json_contains_string(cd, jobj_area, "area", "raw type", "encryption") ||
!json_contains(cd, jobj_area, "area", "raw type", "key_size", json_type_int) ||
!json_contains(cd, jobj_area, "area", "raw type", "offset", json_type_string) ||
!json_contains(cd, jobj_area, "area", "raw type", "size", json_type_string))
!json_contains_string(cd, jobj_area, "area", "raw type", "offset") ||
!json_contains_string(cd, jobj_area, "area", "raw type", "size"))
return -EINVAL;
} else
return -EINVAL;

View File

@@ -310,8 +310,8 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
return -EINVAL;
jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string);
jobj_mode = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "mode");
jobj_direction = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "direction");
if (!jobj_mode || !jobj_direction || !jobj_key_size)
return -EINVAL;
@@ -337,8 +337,8 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
}
if (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) {
jobj_hash = json_contains(cd, jobj_area, "type:checksum",
"Keyslot area", "hash", json_type_string);
jobj_hash = json_contains_string(cd, jobj_area, "type:checksum",
"Keyslot area", "hash");
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum",
"Keyslot area", "sector_size", json_type_int);
if (!jobj_hash || !jobj_sector_size)
@@ -354,8 +354,8 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key
} else if (!strcmp(type, "datashift") ||
!strcmp(type, "datashift-checksum") ||
!strcmp(type, "datashift-journal")) {
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift",
"Keyslot area", "shift_size", json_type_string)))
if (!(jobj_shift_size = json_contains_string(cd, jobj_area, "type:datashift",
"Keyslot area", "shift_size")))
return -EINVAL;
shift_size = crypt_jobj_get_uint64(jobj_shift_size);

View File

@@ -0,0 +1,39 @@
#!/bin/bash
. lib.sh
#
# *** Description ***
#
# generate primary header with segment empty encryption field
#
# secondary header is corrupted on purpose as well
#
# $1 full target dir
# $2 full source luks2 image
function generate()
{
# remove mandatory encryption field
json_str=$(jq -c '.segments."0".encryption = ""' $TMPDIR/json0)
test ${#json_str} -lt $((LUKS2_JSON_SIZE*512)) || exit 2
write_luks2_json "$json_str" $TMPDIR/json0
lib_mangle_json_hdr0_kill_hdr1
}
function check()
{
lib_hdr1_killed || exit 2
read_luks2_json0 $TGT_IMG $TMPDIR/json_res0
jq -c 'if .segments."0".encryption != ""
then error("Unexpected value in result json") else empty end' $TMPDIR/json_res0 || exit 5
}
lib_prepare $@
generate
check
lib_cleanup

View File

@@ -204,6 +204,7 @@ RUN luks2-segment-wrong-flags.img "F" "Failed to detect invalid flags field"
RUN luks2-segment-wrong-flags-element.img "F" "Failed to detect invalid flags content"
RUN luks2-segment-wrong-backup-key-0.img "F" "Failed to detect gap in backup segments"
RUN luks2-segment-wrong-backup-key-1.img "F" "Failed to detect gap in backup segments"
RUN luks2-segment-crypt-empty-encryption.img "F" "Failed to detect empty encryption field"
echo "[6] Test metadata size and keyslots size (config section)"
RUN luks2-invalid-keyslots-size-c0.img "F" "Failed to detect too large keyslots_size in config section"