Blame lib/luks2/luks2_json_metadata.c

Packit 94f725
/*
Packit 94f725
 * LUKS - Linux Unified Key Setup v2
Packit 94f725
 *
Packit 94f725
 * Copyright (C) 2015-2020 Red Hat, Inc. All rights reserved.
Packit 94f725
 * Copyright (C) 2015-2020 Milan Broz
Packit 94f725
 * Copyright (C) 2015-2020 Ondrej Kozina
Packit 94f725
 *
Packit 94f725
 * This program is free software; you can redistribute it and/or
Packit 94f725
 * modify it under the terms of the GNU General Public License
Packit 94f725
 * as published by the Free Software Foundation; either version 2
Packit 94f725
 * of the License, or (at your option) any later version.
Packit 94f725
 *
Packit 94f725
 * This program is distributed in the hope that it will be useful,
Packit 94f725
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 94f725
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 94f725
 * GNU General Public License for more details.
Packit 94f725
 *
Packit 94f725
 * You should have received a copy of the GNU General Public License
Packit 94f725
 * along with this program; if not, write to the Free Software
Packit 94f725
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 94f725
 */
Packit 94f725
Packit 94f725
#include "luks2_internal.h"
Packit 94f725
#include "../integrity/integrity.h"
Packit 94f725
#include <assert.h>
Packit 94f725
#include <ctype.h>
Packit 94f725
#include <uuid/uuid.h>
Packit 94f725
Packit 94f725
#define LUKS_STRIPES 4000
Packit 94f725
Packit 94f725
struct interval {
Packit 94f725
	uint64_t offset;
Packit 94f725
	uint64_t length;
Packit 94f725
};
Packit 94f725
Packit 94f725
void hexprint_base64(struct crypt_device *cd, json_object *jobj,
Packit 94f725
		     const char *sep, const char *line_sep)
Packit 94f725
{
Packit 94f725
	char *buf = NULL;
Packit 94f725
	size_t buf_len;
Packit 94f725
	unsigned int i;
Packit 94f725
Packit 94f725
	if (!base64_decode_alloc(json_object_get_string(jobj),
Packit 94f725
				 json_object_get_string_len(jobj),
Packit 94f725
				 &buf, &buf_len))
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	for (i = 0; i < buf_len; i++) {
Packit 94f725
		if (i && !(i % 16))
Packit 94f725
			log_std(cd, "\n\t%s", line_sep);
Packit 94f725
		log_std(cd, "%02hhx%s", buf[i], sep);
Packit 94f725
	}
Packit 94f725
	log_std(cd, "\n");
Packit 94f725
	free(buf);
Packit 94f725
}
Packit 94f725
Packit 94f725
void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc)
Packit 94f725
{
Packit 94f725
	if (desc)
Packit 94f725
		crypt_log(cd, CRYPT_LOG_DEBUG_JSON, desc);
Packit 94f725
	crypt_log(cd, CRYPT_LOG_DEBUG_JSON, json_object_to_json_string_ext(jobj,
Packit 94f725
		JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE));
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * JSON array helpers
Packit 94f725
 */
Packit 94f725
struct json_object *LUKS2_array_jobj(struct json_object *array, const char *num)
Packit 94f725
{
Packit 94f725
	struct json_object *jobj1;
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	for (i = 0; i < (int) json_object_array_length(array); i++) {
Packit 94f725
		jobj1 = json_object_array_get_idx(array, i);
Packit 94f725
		if (!strcmp(num, json_object_get_string(jobj1)))
Packit 94f725
			return jobj1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return NULL;
Packit 94f725
}
Packit 94f725
Packit 94f725
struct json_object *LUKS2_array_remove(struct json_object *array, const char *num)
Packit 94f725
{
Packit 94f725
	struct json_object *jobj1, *jobj_removing = NULL, *array_new;
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	jobj_removing = LUKS2_array_jobj(array, num);
Packit 94f725
	if (!jobj_removing)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	/* Create new array without jobj_removing. */
Packit 94f725
	array_new = json_object_new_array();
Packit 94f725
	for (i = 0; i < (int) json_object_array_length(array); i++) {
Packit 94f725
		jobj1 = json_object_array_get_idx(array, i);
Packit 94f725
		if (jobj1 != jobj_removing)
Packit 94f725
			json_object_array_add(array_new, json_object_get(jobj1));
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return array_new;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * JSON struct access helpers
Packit 94f725
 */
Packit 94f725
json_object *LUKS2_get_keyslot_jobj(struct luks2_hdr *hdr, int keyslot)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2;
Packit 94f725
	char keyslot_name[16];
Packit 94f725
Packit 94f725
	if (!hdr || keyslot < 0)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj1, keyslot_name, &jobj2))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return jobj2;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_tokens_jobj(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	json_object *jobj_tokens;
Packit 94f725
Packit 94f725
	if (!hdr || !json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return jobj_tokens;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_token_jobj(struct luks2_hdr *hdr, int token)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2;
Packit 94f725
	char token_name[16];
Packit 94f725
Packit 94f725
	if (!hdr || token < 0)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	jobj1 = LUKS2_get_tokens_jobj(hdr);
Packit 94f725
	if (!jobj1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (snprintf(token_name, sizeof(token_name), "%u", token) < 1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(jobj1, token_name, &jobj2);
Packit 94f725
	return jobj2;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_digest_jobj(struct luks2_hdr *hdr, int digest)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2;
Packit 94f725
	char digest_name[16];
Packit 94f725
Packit 94f725
	if (!hdr || digest < 0)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (snprintf(digest_name, sizeof(digest_name), "%u", digest) < 1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "digests", &jobj1))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(jobj1, digest_name, &jobj2);
Packit 94f725
	return jobj2;
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_object *json_get_segments_jobj(json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments;
Packit 94f725
Packit 94f725
	if (!hdr_jobj || !json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return jobj_segments;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_segment_jobj(struct luks2_hdr *hdr, int segment)
Packit 94f725
{
Packit 94f725
	if (!hdr)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (segment == CRYPT_DEFAULT_SEGMENT)
Packit 94f725
		segment = LUKS2_get_default_segment(hdr);
Packit 94f725
Packit 94f725
	return json_segments_get_segment(json_get_segments_jobj(hdr->jobj), segment);
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_segments_jobj(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	return hdr ? json_get_segments_jobj(hdr->jobj) : NULL;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segments_count(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	if (!hdr)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	return json_segments_count(LUKS2_get_segments_jobj(hdr));
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_get_default_segment(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	int s = LUKS2_get_segment_id_by_flag(hdr, "backup-final");
Packit 94f725
	if (s >= 0)
Packit 94f725
		return s;
Packit 94f725
Packit 94f725
	if (LUKS2_segments_count(hdr) == 1)
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	return -EINVAL;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * json_type_int needs to be validated first.
Packit 94f725
 * See validate_json_uint32()
Packit 94f725
 */
Packit 94f725
uint32_t crypt_jobj_get_uint32(json_object *jobj)
Packit 94f725
{
Packit 94f725
	return json_object_get_int64(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
/* jobj has to be json_type_string and numbered */
Packit 94f725
static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
Packit 94f725
{
Packit 94f725
	char *endptr;
Packit 94f725
	unsigned long long tmp;
Packit 94f725
Packit 94f725
	errno = 0;
Packit 94f725
	tmp = strtoull(json_object_get_string(jobj), &endptr, 10);
Packit 94f725
	if (*endptr || errno) {
Packit 94f725
		*value = 0;
Packit 94f725
		return 0;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	*value = tmp;
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t crypt_jobj_get_uint64(json_object *jobj)
Packit 94f725
{
Packit 94f725
	uint64_t r;
Packit 94f725
	json_str_to_uint64(jobj, &r);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *crypt_jobj_new_uint64(uint64_t value)
Packit 94f725
{
Packit 94f725
	/* 18446744073709551615 */
Packit 94f725
	char num[21];
Packit 94f725
	int r;
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	r = snprintf(num, sizeof(num), "%" PRIu64, value);
Packit 94f725
	if (r < 0 || (size_t)r >= sizeof(num))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	jobj = json_object_new_string(num);
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * Validate helpers
Packit 94f725
 */
Packit 94f725
static json_bool numbered(struct crypt_device *cd, const char *name, const char *key)
Packit 94f725
{
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	for (i = 0; key[i]; i++)
Packit 94f725
		if (!isdigit(key[i])) {
Packit 94f725
			log_dbg(cd, "%s \"%s\" is not in numbered form.", name, key);
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
Packit 94f725
			   const char *section, const char *key, json_type type)
Packit 94f725
{
Packit 94f725
	json_object *sobj;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj, key, &sobj) ||
Packit 94f725
	    !json_object_is_type(sobj, type)) {
Packit 94f725
		log_dbg(cd, "%s \"%s\" is missing \"%s\" (%s) specification.",
Packit 94f725
			section, name, key, json_type_to_name(type));
Packit 94f725
		return NULL;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return sobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_bool validate_json_uint32(json_object *jobj)
Packit 94f725
{
Packit 94f725
	int64_t tmp;
Packit 94f725
Packit 94f725
	errno = 0;
Packit 94f725
	tmp = json_object_get_int64(jobj);
Packit 94f725
Packit 94f725
	return (errno || tmp < 0 || tmp > UINT32_MAX) ? 0 : 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_bool validate_keyslots_array(struct crypt_device *cd,
Packit 94f725
					 json_object *jarr, json_object *jobj_keys)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
	int i = 0, length = (int) json_object_array_length(jarr);
Packit 94f725
Packit 94f725
	while (i < length) {
Packit 94f725
		jobj = json_object_array_get_idx(jarr, i);
Packit 94f725
		if (!json_object_is_type(jobj, json_type_string)) {
Packit 94f725
			log_dbg(cd, "Illegal value type in keyslots array at index %d.", i);
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (!json_contains(cd, jobj_keys, "", "Keyslots section",
Packit 94f725
				   json_object_get_string(jobj), json_type_object))
Packit 94f725
			return 0;
Packit 94f725
Packit 94f725
		i++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_bool validate_segments_array(struct crypt_device *cd,
Packit 94f725
					 json_object *jarr, json_object *jobj_segments)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
	int i = 0, length = (int) json_object_array_length(jarr);
Packit 94f725
Packit 94f725
	while (i < length) {
Packit 94f725
		jobj = json_object_array_get_idx(jarr, i);
Packit 94f725
		if (!json_object_is_type(jobj, json_type_string)) {
Packit 94f725
			log_dbg(cd, "Illegal value type in segments array at index %d.", i);
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (!json_contains(cd, jobj_segments, "", "Segments section",
Packit 94f725
				   json_object_get_string(jobj), json_type_object))
Packit 94f725
			return 0;
Packit 94f725
Packit 94f725
		i++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_bool segment_has_digest(const char *segment_name, json_object *jobj_digests)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_digests, key, val) {
Packit 94f725
		UNUSED(key);
Packit 94f725
		json_object_object_get_ex(val, "segments", &jobj_segments);
Packit 94f725
		if (LUKS2_array_jobj(jobj_segments, segment_name))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_bool validate_intervals(struct crypt_device *cd,
Packit 94f725
				    int length, const struct interval *ix,
Packit 94f725
				    uint64_t metadata_size, uint64_t keyslots_area_end)
Packit 94f725
{
Packit 94f725
	int j, i = 0;
Packit 94f725
Packit 94f725
	while (i < length) {
Packit 94f725
		if (ix[i].offset < 2 * metadata_size) {
Packit 94f725
			log_dbg(cd, "Illegal area offset: %" PRIu64 ".", ix[i].offset);
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (!ix[i].length) {
Packit 94f725
			log_dbg(cd, "Area length must be greater than zero.");
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if ((ix[i].offset + ix[i].length) > keyslots_area_end) {
Packit 94f725
			log_dbg(cd, "Area [%" PRIu64 ", %" PRIu64 "] overflows binary keyslots area (ends at offset: %" PRIu64 ").",
Packit 94f725
				ix[i].offset, ix[i].offset + ix[i].length, keyslots_area_end);
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		for (j = 0; j < length; j++) {
Packit 94f725
			if (i == j)
Packit 94f725
				continue;
Packit 94f725
			if ((ix[i].offset >= ix[j].offset) && (ix[i].offset < (ix[j].offset + ix[j].length))) {
Packit 94f725
				log_dbg(cd, "Overlapping areas [%" PRIu64 ",%" PRIu64 "] and [%" PRIu64 ",%" PRIu64 "].",
Packit 94f725
					ix[i].offset, ix[i].offset + ix[i].length,
Packit 94f725
					ix[j].offset, ix[j].offset + ix[j].length);
Packit 94f725
				return 0;
Packit 94f725
			}
Packit 94f725
		}
Packit 94f725
Packit 94f725
		i++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int LUKS2_keyslot_validate(struct crypt_device *cd, json_object *hdr_jobj, json_object *hdr_keyslot, const char *key)
Packit 94f725
{
Packit 94f725
	json_object *jobj_key_size;
Packit 94f725
Packit 94f725
	if (!json_contains(cd, hdr_keyslot, key, "Keyslot", "type", json_type_string))
Packit 94f725
		return 1;
Packit 94f725
	if (!(jobj_key_size = json_contains(cd, hdr_keyslot, key, "Keyslot", "key_size", json_type_int)))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* enforce uint32_t type */
Packit 94f725
	if (!validate_json_uint32(jobj_key_size)) {
Packit 94f725
		log_dbg(cd, "Illegal field \"key_size\":%s.",
Packit 94f725
			json_object_get_string(jobj_key_size));
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_token_validate(struct crypt_device *cd,
Packit 94f725
			 json_object *hdr_jobj, json_object *jobj_token, const char *key)
Packit 94f725
{
Packit 94f725
	json_object *jarr, *jobj_keyslots;
Packit 94f725
Packit 94f725
	/* keyslots are not yet validated, but we need to know token doesn't reference missing keyslot */
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	if (!json_contains(cd, jobj_token, key, "Token", "type", json_type_string))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	jarr = json_contains(cd, jobj_token, key, "Token", "keyslots", json_type_array);
Packit 94f725
	if (!jarr)
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	if (!validate_keyslots_array(cd, jarr, jobj_keyslots))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_json_size(struct crypt_device *cd, json_object *hdr_jobj, uint64_t hdr_json_size)
Packit 94f725
{
Packit 94f725
	json_object *jobj, *jobj1;
Packit 94f725
	const char *json;
Packit 94f725
	uint64_t json_area_size, json_size;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(hdr_jobj, "config", &jobj);
Packit 94f725
	json_object_object_get_ex(jobj, "json_size", &jobj1);
Packit 94f725
Packit 94f725
	json = json_object_to_json_string_ext(hdr_jobj,
Packit 94f725
		JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE);
Packit 94f725
	json_area_size = crypt_jobj_get_uint64(jobj1);
Packit 94f725
	json_size = (uint64_t)strlen(json);
Packit 94f725
Packit 94f725
	if (hdr_json_size != json_area_size) {
Packit 94f725
		log_dbg(cd, "JSON area size does not match value in binary header.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (json_size > json_area_size) {
Packit 94f725
		log_dbg(cd, "JSON does not fit in the designated area.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_check_json_size(struct crypt_device *cd, const struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	return hdr_validate_json_size(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN);
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj)) {
Packit 94f725
		log_dbg(cd, "Missing keyslots section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj, key, val) {
Packit 94f725
		if (!numbered(cd, "Keyslot", key))
Packit 94f725
			return 1;
Packit 94f725
		if (LUKS2_keyslot_validate(cd, hdr_jobj, val, key))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_tokens(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "tokens", &jobj)) {
Packit 94f725
		log_dbg(cd, "Missing tokens section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj, key, val) {
Packit 94f725
		if (!numbered(cd, "Token", key))
Packit 94f725
			return 1;
Packit 94f725
		if (LUKS2_token_validate(cd, hdr_jobj, val, key))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_crypt_segment(struct crypt_device *cd,
Packit 94f725
				      json_object *jobj, const char *key, json_object *jobj_digests,
Packit 94f725
	uint64_t offset, uint64_t size)
Packit 94f725
{
Packit 94f725
	json_object *jobj_ivoffset, *jobj_sector_size, *jobj_integrity;
Packit 94f725
	uint32_t sector_size;
Packit 94f725
	uint64_t ivoffset;
Packit 94f725
Packit 94f725
	if (!(jobj_ivoffset = json_contains(cd, jobj, key, "Segment", "iv_tweak", json_type_string)) ||
Packit 94f725
	    !json_contains(cd, jobj, key, "Segment", "encryption", json_type_string) ||
Packit 94f725
	    !(jobj_sector_size = json_contains(cd, jobj, key, "Segment", "sector_size", json_type_int)))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* integrity */
Packit 94f725
	if (json_object_object_get_ex(jobj, "integrity", &jobj_integrity)) {
Packit 94f725
		if (!json_contains(cd, jobj, key, "Segment", "integrity", json_type_object) ||
Packit 94f725
		    !json_contains(cd, jobj_integrity, key, "Segment integrity", "type", json_type_string) ||
Packit 94f725
		    !json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_encryption", json_type_string) ||
Packit 94f725
		    !json_contains(cd, jobj_integrity, key, "Segment integrity", "journal_integrity", json_type_string))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* enforce uint32_t type */
Packit 94f725
	if (!validate_json_uint32(jobj_sector_size)) {
Packit 94f725
		log_dbg(cd, "Illegal field \"sector_size\":%s.",
Packit 94f725
			json_object_get_string(jobj_sector_size));
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	sector_size = crypt_jobj_get_uint32(jobj_sector_size);
Packit 94f725
	if (!sector_size || MISALIGNED_512(sector_size)) {
Packit 94f725
		log_dbg(cd, "Illegal sector size: %" PRIu32, sector_size);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (!numbered(cd, "iv_tweak", json_object_get_string(jobj_ivoffset)) ||
Packit 94f725
	    !json_str_to_uint64(jobj_ivoffset, &ivoffset)) {
Packit 94f725
		log_dbg(cd, "Illegal iv_tweak value.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (size % sector_size) {
Packit 94f725
		log_dbg(cd, "Size field has to be aligned to sector size: %" PRIu32, sector_size);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return !segment_has_digest(key, jobj_digests);
Packit 94f725
}
Packit 94f725
Packit 94f725
static bool validate_segment_intervals(struct crypt_device *cd,
Packit 94f725
				    int length, const struct interval *ix)
Packit 94f725
{
Packit 94f725
	int j, i = 0;
Packit 94f725
Packit 94f725
	while (i < length) {
Packit 94f725
		if (ix[i].length == UINT64_MAX && (i != (length - 1))) {
Packit 94f725
			log_dbg(cd, "Only last regular segment is allowed to have 'dynamic' size.");
Packit 94f725
			return false;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		for (j = 0; j < length; j++) {
Packit 94f725
			if (i == j)
Packit 94f725
				continue;
Packit 94f725
			if ((ix[i].offset >= ix[j].offset) && (ix[j].length == UINT64_MAX || (ix[i].offset < (ix[j].offset + ix[j].length)))) {
Packit 94f725
				log_dbg(cd, "Overlapping segments [%" PRIu64 ",%" PRIu64 "]%s and [%" PRIu64 ",%" PRIu64 "]%s.",
Packit 94f725
					ix[i].offset, ix[i].offset + ix[i].length, ix[i].length == UINT64_MAX ? "(dynamic)" : "",
Packit 94f725
					ix[j].offset, ix[j].offset + ix[j].length, ix[j].length == UINT64_MAX ? "(dynamic)" : "");
Packit 94f725
				return false;
Packit 94f725
			}
Packit 94f725
		}
Packit 94f725
Packit 94f725
		i++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return true;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj;
Packit 94f725
	uint64_t offset, size;
Packit 94f725
	int i, r, count, first_backup = -1;
Packit Service 2b0da5
	struct interval *intervals = NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) {
Packit 94f725
		log_dbg(cd, "Missing segments section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	count = json_object_object_length(jobj_segments);
Packit 94f725
	if (count < 1) {
Packit 94f725
		log_dbg(cd, "Empty segments section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* digests should already be validated */
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, key, val) {
Packit 94f725
		if (!numbered(cd, "Segment", key))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		/* those fields are mandatory for all segment types */
Packit 94f725
		if (!(jobj_type =   json_contains(cd, val, key, "Segment", "type",   json_type_string)) ||
Packit 94f725
		    !(jobj_offset = json_contains(cd, val, key, "Segment", "offset", json_type_string)) ||
Packit 94f725
		    !(jobj_size =   json_contains(cd, val, key, "Segment", "size",   json_type_string)))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		if (!numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
Packit 94f725
		    !json_str_to_uint64(jobj_offset, &offset))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		/* size "dynamic" means whole device starting at 'offset' */
Packit 94f725
		if (strcmp(json_object_get_string(jobj_size), "dynamic")) {
Packit 94f725
			if (!numbered(cd, "size", json_object_get_string(jobj_size)) ||
Packit 94f725
			    !json_str_to_uint64(jobj_size, &size) || !size)
Packit 94f725
				return 1;
Packit 94f725
		} else
Packit 94f725
			size = 0;
Packit 94f725
Packit 94f725
		/* all device-mapper devices are aligned to 512 sector size */
Packit 94f725
		if (MISALIGNED_512(offset)) {
Packit 94f725
			log_dbg(cd, "Offset field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
		if (MISALIGNED_512(size)) {
Packit 94f725
			log_dbg(cd, "Size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		/* flags array is optional and must contain strings */
Packit 94f725
		if (json_object_object_get_ex(val, "flags", NULL)) {
Packit 94f725
			if (!(jobj_flags = json_contains(cd, val, key, "Segment", "flags", json_type_array)))
Packit 94f725
				return 1;
Packit 94f725
			for (i = 0; i < (int) json_object_array_length(jobj_flags); i++)
Packit 94f725
				if (!json_object_is_type(json_object_array_get_idx(jobj_flags, i), json_type_string))
Packit 94f725
					return 1;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		i = atoi(key);
Packit 94f725
		if (json_segment_is_backup(val)) {
Packit 94f725
			if (first_backup < 0 || i < first_backup)
Packit 94f725
				first_backup = i;
Packit 94f725
		} else {
Packit 94f725
			if ((first_backup >= 0) && i >= first_backup) {
Packit 94f725
				log_dbg(cd, "Regular segment at %d is behind backup segment at %d", i, first_backup);
Packit 94f725
				return 1;
Packit 94f725
			}
Packit 94f725
		}
Packit 94f725
Packit 94f725
		/* crypt */
Packit 94f725
		if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
Packit 94f725
		    hdr_validate_crypt_segment(cd, val, key, jobj_digests, offset, size))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (first_backup == 0) {
Packit 94f725
		log_dbg(cd, "No regular segment.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit Service 2b0da5
	/* avoid needlessly large allocation when first backup segment is invalid */
Packit Service 2b0da5
	if (first_backup >= count) {
Packit Service 2b0da5
		log_dbg(cd, "Gap between last regular segment and backup segment at key %d.", first_backup);
Packit Service 2b0da5
		return 1;
Packit Service 2b0da5
	}
Packit Service 2b0da5
Packit 94f725
	if (first_backup < 0)
Packit 94f725
		first_backup = count;
Packit 94f725
Packit Service 2b0da5
	if ((size_t)first_backup < SIZE_MAX / sizeof(*intervals))
Packit Service 2b0da5
		intervals = malloc(first_backup * sizeof(*intervals));
Packit Service 2b0da5
Packit 94f725
	if (!intervals) {
Packit 94f725
		log_dbg(cd, "Not enough memory.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	for (i = 0; i < first_backup; i++) {
Packit 94f725
		jobj = json_segments_get_segment(jobj_segments, i);
Packit 94f725
		if (!jobj) {
Packit 94f725
			log_dbg(cd, "Gap at key %d in segments object.", i);
Packit 94f725
			free(intervals);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
		intervals[i].offset = json_segment_get_offset(jobj, 0);
Packit 94f725
		intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = !validate_segment_intervals(cd, first_backup, intervals);
Packit 94f725
	free(intervals);
Packit 94f725
Packit 94f725
	if (r)
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	for (; i < count; i++) {
Packit 94f725
		if (!json_segments_get_segment(jobj_segments, i)) {
Packit 94f725
			log_dbg(cd, "Gap at key %d in segments object.", i);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_metadata_size(json_object *jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2;
Packit 94f725
	uint64_t json_size;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(jobj, "config", &jobj1);
Packit 94f725
	json_object_object_get_ex(jobj1, "json_size", &jobj2);
Packit 94f725
	json_str_to_uint64(jobj2, &json_size);
Packit 94f725
Packit 94f725
	return json_size + LUKS2_HDR_BIN_LEN;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_areas(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	struct interval *intervals;
Packit 94f725
	json_object *jobj_keyslots, *jobj_offset, *jobj_length, *jobj_segments, *jobj_area;
Packit 94f725
	int length, ret, i = 0;
Packit 94f725
	uint64_t metadata_size;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* segments are already validated */
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* config is already validated */
Packit 94f725
	metadata_size = LUKS2_metadata_size(hdr_jobj);
Packit 94f725
Packit 94f725
	length = json_object_object_length(jobj_keyslots);
Packit 94f725
Packit 94f725
	/* Empty section */
Packit 94f725
	if (length == 0)
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (length < 0) {
Packit 94f725
		log_dbg(cd, "Invalid keyslot areas specification.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	intervals = malloc(length * sizeof(*intervals));
Packit 94f725
	if (!intervals) {
Packit 94f725
		log_dbg(cd, "Not enough memory.");
Packit 94f725
		return -ENOMEM;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_keyslots, key, val) {
Packit 94f725
Packit 94f725
		if (!(jobj_area = json_contains(cd, val, key, "Keyslot", "area", json_type_object)) ||
Packit 94f725
		    !json_contains(cd, jobj_area, key, "Keyslot area", "type", json_type_string) ||
Packit 94f725
		    !(jobj_offset = json_contains(cd, jobj_area, key, "Keyslot", "offset", json_type_string)) ||
Packit 94f725
		    !(jobj_length = json_contains(cd, jobj_area, key, "Keyslot", "size", json_type_string)) ||
Packit 94f725
		    !numbered(cd, "offset", json_object_get_string(jobj_offset)) ||
Packit 94f725
		    !numbered(cd, "size", json_object_get_string(jobj_length))) {
Packit 94f725
			free(intervals);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		/* rule out values > UINT64_MAX */
Packit 94f725
		if (!json_str_to_uint64(jobj_offset, &intervals[i].offset) ||
Packit 94f725
		    !json_str_to_uint64(jobj_length, &intervals[i].length)) {
Packit 94f725
			free(intervals);
Packit 94f725
			return 1;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		i++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (length != i) {
Packit 94f725
		free(intervals);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	ret = validate_intervals(cd, length, intervals, metadata_size, LUKS2_hdr_and_areas_size(hdr_jobj)) ? 0 : 1;
Packit 94f725
Packit 94f725
	free(intervals);
Packit 94f725
Packit 94f725
	return ret;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jarr_keys, *jarr_segs, *jobj, *jobj_keyslots, *jobj_segments;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj)) {
Packit 94f725
		log_dbg(cd, "Missing digests section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* keyslots are not yet validated, but we need to know digest doesn't reference missing keyslot */
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* segments are not yet validated, but we need to know digest doesn't reference missing segment */
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj, key, val) {
Packit 94f725
		if (!numbered(cd, "Digest", key))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		if (!json_contains(cd, val, key, "Digest", "type", json_type_string) ||
Packit 94f725
		    !(jarr_keys = json_contains(cd, val, key, "Digest", "keyslots", json_type_array)) ||
Packit 94f725
		    !(jarr_segs = json_contains(cd, val, key, "Digest", "segments", json_type_array)))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		if (!validate_keyslots_array(cd, jarr_keys, jobj_keyslots))
Packit 94f725
			return 1;
Packit 94f725
		if (!validate_segments_array(cd, jarr_segs, jobj_segments))
Packit 94f725
			return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj_config, *jobj, *jobj1;
Packit 94f725
	int i;
Packit 94f725
	uint64_t keyslots_size, metadata_size, segment_offset;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
Packit 94f725
		log_dbg(cd, "Missing config section.");
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "json_size", json_type_string)) ||
Packit 94f725
	    !json_str_to_uint64(jobj, &metadata_size))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* single metadata instance is assembled from json area size plus
Packit 94f725
	 * binary header size */
Packit 94f725
	metadata_size += LUKS2_HDR_BIN_LEN;
Packit 94f725
Packit 94f725
	if (!(jobj = json_contains(cd, jobj_config, "section", "Config", "keyslots_size", json_type_string)) ||
Packit 94f725
	    !json_str_to_uint64(jobj, &keyslots_size))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	if (LUKS2_check_metadata_area_size(metadata_size)) {
Packit 94f725
		log_dbg(cd, "Unsupported LUKS2 header size (%" PRIu64 ").", metadata_size);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (LUKS2_check_keyslots_area_size(keyslots_size)) {
Packit 94f725
		log_dbg(cd, "Unsupported LUKS2 keyslots size (%" PRIu64 ").", keyslots_size);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/*
Packit 94f725
	 * validate keyslots_size fits in between (2 * metadata_size) and first
Packit 94f725
	 * segment_offset (except detached header)
Packit 94f725
	 */
Packit 94f725
	segment_offset = json_segments_get_minimal_offset(json_get_segments_jobj(hdr_jobj), 0);
Packit 94f725
	if (segment_offset &&
Packit 94f725
	    (segment_offset < keyslots_size ||
Packit 94f725
	     (segment_offset - keyslots_size) < (2 * metadata_size))) {
Packit 94f725
		log_dbg(cd, "keyslots_size is too large %" PRIu64 " (bytes). Data offset: %" PRIu64
Packit 94f725
			", keyslots offset: %" PRIu64, keyslots_size, segment_offset, 2 * metadata_size);
Packit 94f725
		return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* Flags array is optional */
Packit 94f725
	if (json_object_object_get_ex(jobj_config, "flags", &jobj)) {
Packit 94f725
		if (!json_contains(cd, jobj_config, "section", "Config", "flags", json_type_array))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		/* All array members must be strings */
Packit 94f725
		for (i = 0; i < (int) json_object_array_length(jobj); i++)
Packit 94f725
			if (!json_object_is_type(json_object_array_get_idx(jobj, i), json_type_string))
Packit 94f725
				return 1;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* Requirements object is optional */
Packit 94f725
	if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) {
Packit 94f725
		if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
		/* Mandatory array is optional */
Packit 94f725
		if (json_object_object_get_ex(jobj, "mandatory", &jobj1)) {
Packit 94f725
			if (!json_contains(cd, jobj, "section", "Requirements", "mandatory", json_type_array))
Packit 94f725
				return 1;
Packit 94f725
Packit 94f725
			/* All array members must be strings */
Packit 94f725
			for (i = 0; i < (int) json_object_array_length(jobj1); i++)
Packit 94f725
				if (!json_object_is_type(json_object_array_get_idx(jobj1, i), json_type_string))
Packit 94f725
					return 1;
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t json_size)
Packit 94f725
{
Packit 94f725
	struct {
Packit 94f725
		int (*validate)(struct crypt_device *, json_object *);
Packit 94f725
	} checks[] = {
Packit 94f725
		{ hdr_validate_tokens   },
Packit 94f725
		{ hdr_validate_digests  },
Packit 94f725
		{ hdr_validate_segments },
Packit 94f725
		{ hdr_validate_keyslots },
Packit 94f725
		{ hdr_validate_config   },
Packit 94f725
		{ hdr_validate_areas    },
Packit 94f725
		{ NULL }
Packit 94f725
	};
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	if (!hdr_jobj)
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	for (i = 0; checks[i].validate; i++)
Packit 94f725
		if (checks[i].validate && checks[i].validate(cd, hdr_jobj))
Packit 94f725
			return 1;
Packit 94f725
Packit 94f725
	if (hdr_validate_json_size(cd, hdr_jobj, json_size))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	/* validate keyslot implementations */
Packit 94f725
	if (LUKS2_keyslots_validate(cd, hdr_jobj))
Packit 94f725
		return 1;
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
/* FIXME: should we expose do_recovery parameter explicitly? */
Packit 94f725
int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair)
Packit 94f725
{
Packit 94f725
	int r;
Packit 94f725
Packit 94f725
	r = device_read_lock(cd, crypt_metadata_device(cd));
Packit 94f725
	if (r) {
Packit 94f725
		log_err(cd, _("Failed to acquire read lock on device %s."),
Packit 94f725
			device_path(crypt_metadata_device(cd)));
Packit 94f725
		return r;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
Packit 94f725
	if (r == -EAGAIN) {
Packit 94f725
		/* unlikely: auto-recovery is required and failed due to read lock being held */
Packit 94f725
		device_read_unlock(cd, crypt_metadata_device(cd));
Packit 94f725
Packit 94f725
		/* Do not use LUKS2_device_write lock. Recovery. */
Packit 94f725
		r = device_write_lock(cd, crypt_metadata_device(cd));
Packit 94f725
		if (r < 0) {
Packit 94f725
			log_err(cd, _("Failed to acquire write lock on device %s."),
Packit 94f725
				device_path(crypt_metadata_device(cd)));
Packit 94f725
			return r;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, !repair);
Packit 94f725
Packit 94f725
		device_write_unlock(cd, crypt_metadata_device(cd));
Packit 94f725
	} else
Packit 94f725
		device_read_unlock(cd, crypt_metadata_device(cd));
Packit 94f725
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int hdr_cleanup_and_validate(struct crypt_device *cd, struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	LUKS2_digests_erase_unused(cd, hdr);
Packit 94f725
Packit 94f725
	return LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	if (hdr_cleanup_and_validate(cd, hdr))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), false);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	if (hdr_cleanup_and_validate(cd, hdr))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), true);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *uuid)
Packit 94f725
{
Packit 94f725
	uuid_t partitionUuid;
Packit 94f725
Packit 94f725
	if (uuid && uuid_parse(uuid, partitionUuid) == -1) {
Packit 94f725
		log_err(cd, _("Wrong LUKS UUID format provided."));
Packit 94f725
		return -EINVAL;
Packit 94f725
	}
Packit 94f725
	if (!uuid)
Packit 94f725
		uuid_generate(partitionUuid);
Packit 94f725
Packit 94f725
	uuid_unparse(partitionUuid, hdr->uuid);
Packit 94f725
Packit 94f725
	return LUKS2_hdr_write(cd, hdr);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_labels(struct crypt_device *cd, struct luks2_hdr *hdr,
Packit 94f725
		     const char *label, const char *subsystem, int commit)
Packit 94f725
{
Packit 94f725
	//FIXME: check if the labels are the same and skip this.
Packit 94f725
Packit 94f725
	memset(hdr->label, 0, LUKS2_LABEL_L);
Packit 94f725
	if (label)
Packit 94f725
		strncpy(hdr->label, label, LUKS2_LABEL_L-1);
Packit 94f725
Packit 94f725
	memset(hdr->subsystem, 0, LUKS2_LABEL_L);
Packit 94f725
	if (subsystem)
Packit 94f725
		strncpy(hdr->subsystem, subsystem, LUKS2_LABEL_L-1);
Packit 94f725
Packit 94f725
	return commit ? LUKS2_hdr_write(cd, hdr) : 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
void LUKS2_hdr_free(struct crypt_device *cd, struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	if (json_object_put(hdr->jobj))
Packit 94f725
		hdr->jobj = NULL;
Packit 94f725
	else if (hdr->jobj)
Packit 94f725
		log_dbg(cd, "LUKS2 header still in use");
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_keyslots_size(json_object *jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2;
Packit 94f725
	uint64_t keyslots_size;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(jobj, "config", &jobj1);
Packit 94f725
	json_object_object_get_ex(jobj1, "keyslots_size", &jobj2);
Packit 94f725
	json_str_to_uint64(jobj2, &keyslots_size);
Packit 94f725
Packit 94f725
	return keyslots_size;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_hdr_and_areas_size(json_object *jobj)
Packit 94f725
{
Packit 94f725
	return 2 * LUKS2_metadata_size(jobj) + LUKS2_keyslots_size(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr,
Packit 94f725
		     const char *backup_file)
Packit 94f725
{
Packit 94f725
	struct device *device = crypt_metadata_device(cd);
Packit 94f725
	int fd, devfd, r = 0;
Packit 94f725
	ssize_t hdr_size;
Packit 94f725
	ssize_t ret, buffer_size;
Packit 94f725
	char *buffer = NULL;
Packit 94f725
Packit 94f725
	hdr_size = LUKS2_hdr_and_areas_size(hdr->jobj);
Packit 94f725
	buffer_size = size_round_up(hdr_size, crypt_getpagesize());
Packit 94f725
Packit 94f725
	buffer = crypt_safe_alloc(buffer_size);
Packit 94f725
	if (!buffer)
Packit 94f725
		return -ENOMEM;
Packit 94f725
Packit 94f725
	log_dbg(cd, "Storing backup of header (%zu bytes).", hdr_size);
Packit 94f725
	log_dbg(cd, "Output backup file size: %zu bytes.", buffer_size);
Packit 94f725
Packit 94f725
	r = device_read_lock(cd, device);
Packit 94f725
	if (r) {
Packit 94f725
		log_err(cd, _("Failed to acquire read lock on device %s."),
Packit 94f725
			device_path(crypt_metadata_device(cd)));
Packit 94f725
		crypt_safe_free(buffer);
Packit 94f725
		return r;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	devfd = device_open_locked(cd, device, O_RDONLY);
Packit 94f725
	if (devfd < 0) {
Packit 94f725
		device_read_unlock(cd, device);
Packit 94f725
		log_err(cd, _("Device %s is not a valid LUKS device."), device_path(device));
Packit 94f725
		crypt_safe_free(buffer);
Packit 94f725
		return devfd == -1 ? -EINVAL : devfd;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (read_lseek_blockwise(devfd, device_block_size(cd, device),
Packit 94f725
			   device_alignment(device), buffer, hdr_size, 0) < hdr_size) {
Packit 94f725
		device_read_unlock(cd, device);
Packit 94f725
		crypt_safe_free(buffer);
Packit 94f725
		return -EIO;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	device_read_unlock(cd, device);
Packit 94f725
Packit 94f725
	fd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
Packit 94f725
	if (fd == -1) {
Packit 94f725
		if (errno == EEXIST)
Packit 94f725
			log_err(cd, _("Requested header backup file %s already exists."), backup_file);
Packit 94f725
		else
Packit 94f725
			log_err(cd, _("Cannot create header backup file %s."), backup_file);
Packit 94f725
		crypt_safe_free(buffer);
Packit 94f725
		return -EINVAL;
Packit 94f725
	}
Packit 94f725
	ret = write_buffer(fd, buffer, buffer_size);
Packit 94f725
	close(fd);
Packit 94f725
	if (ret < buffer_size) {
Packit 94f725
		log_err(cd, _("Cannot write header backup file %s."), backup_file);
Packit 94f725
		r = -EIO;
Packit 94f725
	} else
Packit 94f725
		r = 0;
Packit 94f725
Packit 94f725
	crypt_safe_free(buffer);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int reqs_unknown(uint32_t reqs)
Packit 94f725
{
Packit 94f725
	return reqs & CRYPT_REQUIREMENT_UNKNOWN;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int reqs_reencrypt(uint32_t reqs)
Packit 94f725
{
Packit 94f725
	return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int reqs_reencrypt_online(uint32_t reqs)
Packit 94f725
{
Packit 94f725
	return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
Packit 94f725
		     const char *backup_file)
Packit 94f725
{
Packit 94f725
	struct device *backup_device, *device = crypt_metadata_device(cd);
Packit 94f725
	int r, fd, devfd = -1, diff_uuid = 0;
Packit 94f725
	ssize_t ret, buffer_size = 0;
Packit 94f725
	char *buffer = NULL, msg[1024];
Packit 94f725
	struct luks2_hdr hdr_file;
Packit 94f725
	struct luks2_hdr tmp_hdr = {};
Packit 94f725
	uint32_t reqs = 0;
Packit 94f725
Packit 94f725
	r = device_alloc(cd, &backup_device, backup_file);
Packit 94f725
	if (r < 0)
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	r = device_read_lock(cd, backup_device);
Packit 94f725
	if (r) {
Packit 94f725
		log_err(cd, _("Failed to acquire read lock on device %s."),
Packit 94f725
			device_path(backup_device));
Packit 94f725
		device_free(cd, backup_device);
Packit 94f725
		return r;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = LUKS2_disk_hdr_read(cd, &hdr_file, backup_device, 0, 0);
Packit 94f725
	device_read_unlock(cd, backup_device);
Packit 94f725
	device_free(cd, backup_device);
Packit 94f725
Packit 94f725
	if (r < 0) {
Packit 94f725
		log_err(cd, _("Backup file does not contain valid LUKS header."));
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* do not allow header restore from backup with unmet requirements */
Packit 94f725
	if (LUKS2_unmet_requirements(cd, &hdr_file, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1)) {
Packit 94f725
		log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
Packit 94f725
			backup_file);
Packit 94f725
		r = -ETXTBSY;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	buffer_size = LUKS2_hdr_and_areas_size(hdr_file.jobj);
Packit 94f725
	buffer = crypt_safe_alloc(buffer_size);
Packit 94f725
	if (!buffer) {
Packit 94f725
		r = -ENOMEM;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	fd = open(backup_file, O_RDONLY);
Packit 94f725
	if (fd == -1) {
Packit 94f725
		log_err(cd, _("Cannot open header backup file %s."), backup_file);
Packit 94f725
		r = -EINVAL;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	ret = read_buffer(fd, buffer, buffer_size);
Packit 94f725
	close(fd);
Packit 94f725
	if (ret < buffer_size) {
Packit 94f725
		log_err(cd, _("Cannot read header backup file %s."), backup_file);
Packit 94f725
		r = -EIO;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = LUKS2_hdr_read(cd, &tmp_hdr, 0);
Packit 94f725
	if (r == 0) {
Packit 94f725
		log_dbg(cd, "Device %s already contains LUKS2 header, checking UUID and requirements.", device_path(device));
Packit 94f725
		r = LUKS2_config_get_requirements(cd, &tmp_hdr, &reqs);
Packit 94f725
		if (r)
Packit 94f725
			goto out;
Packit 94f725
Packit 94f725
		if (memcmp(tmp_hdr.uuid, hdr_file.uuid, LUKS2_UUID_L))
Packit 94f725
			diff_uuid = 1;
Packit 94f725
Packit 94f725
		if (!reqs_reencrypt(reqs)) {
Packit 94f725
			log_dbg(cd, "Checking LUKS2 header size and offsets.");
Packit 94f725
			if (LUKS2_get_data_offset(&tmp_hdr) != LUKS2_get_data_offset(&hdr_file)) {
Packit 94f725
				log_err(cd, _("Data offset differ on device and backup, restore failed."));
Packit 94f725
				r = -EINVAL;
Packit 94f725
				goto out;
Packit 94f725
			}
Packit 94f725
			/* FIXME: what could go wrong? Erase if we're fine with consequences */
Packit 94f725
			if (buffer_size != (ssize_t) LUKS2_hdr_and_areas_size(tmp_hdr.jobj)) {
Packit 94f725
				log_err(cd, _("Binary header with keyslot areas size differ on device and backup, restore failed."));
Packit 94f725
				r = -EINVAL;
Packit 94f725
				goto out;
Packit 94f725
			}
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = snprintf(msg, sizeof(msg), _("Device %s %s%s%s%s"), device_path(device),
Packit 94f725
		     r ? _("does not contain LUKS2 header. Replacing header can destroy data on that device.") :
Packit 94f725
			 _("already contains LUKS2 header. Replacing header will destroy existing keyslots."),
Packit 94f725
		     diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "",
Packit 94f725
		     reqs_unknown(reqs) ? _("\nWARNING: unknown LUKS2 requirements detected in real device header!"
Packit 94f725
					    "\nReplacing header with backup may corrupt the data on that device!") : "",
Packit 94f725
		     reqs_reencrypt(reqs) ? _("\nWARNING: Unfinished offline reencryption detected on the device!"
Packit 94f725
					      "\nReplacing header with backup may corrupt data.") : "");
Packit 94f725
	if (r < 0 || (size_t) r >= sizeof(msg)) {
Packit 94f725
		r = -ENOMEM;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (!crypt_confirm(cd, msg)) {
Packit 94f725
		r = -EINVAL;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	log_dbg(cd, "Storing backup of header (%zu bytes) to device %s.", buffer_size, device_path(device));
Packit 94f725
Packit 94f725
	/* Do not use LUKS2_device_write lock for checking sequence id on restore */
Packit 94f725
	r = device_write_lock(cd, device);
Packit 94f725
	if (r < 0) {
Packit 94f725
		log_err(cd, _("Failed to acquire write lock on device %s."),
Packit 94f725
			device_path(device));
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	devfd = device_open_locked(cd, device, O_RDWR);
Packit 94f725
	if (devfd < 0) {
Packit 94f725
		if (errno == EACCES)
Packit 94f725
			log_err(cd, _("Cannot write to device %s, permission denied."),
Packit 94f725
				device_path(device));
Packit 94f725
		else
Packit 94f725
			log_err(cd, _("Cannot open device %s."), device_path(device));
Packit 94f725
		device_write_unlock(cd, device);
Packit 94f725
		r = -EINVAL;
Packit 94f725
		goto out;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (write_lseek_blockwise(devfd, device_block_size(cd, device),
Packit 94f725
			    device_alignment(device), buffer, buffer_size, 0) < buffer_size)
Packit 94f725
		r = -EIO;
Packit 94f725
	else
Packit 94f725
		r = 0;
Packit 94f725
Packit 94f725
	device_write_unlock(cd, device);
Packit 94f725
out:
Packit 94f725
	LUKS2_hdr_free(cd, hdr);
Packit 94f725
	LUKS2_hdr_free(cd, &hdr_file);
Packit 94f725
	LUKS2_hdr_free(cd, &tmp_hdr);
Packit 94f725
	crypt_safe_memzero(&hdr_file, sizeof(hdr_file));
Packit 94f725
	crypt_safe_memzero(&tmp_hdr, sizeof(tmp_hdr));
Packit 94f725
	crypt_safe_free(buffer);
Packit 94f725
Packit 94f725
	device_sync(cd, device);
Packit 94f725
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * Persistent config flags
Packit 94f725
 */
Packit 94f725
static const struct  {
Packit 94f725
	uint32_t flag;
Packit 94f725
	const char *description;
Packit 94f725
} persistent_flags[] = {
Packit 94f725
	{ CRYPT_ACTIVATE_ALLOW_DISCARDS,         "allow-discards" },
Packit 94f725
	{ CRYPT_ACTIVATE_SAME_CPU_CRYPT,         "same-cpu-crypt" },
Packit 94f725
	{ CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS, "submit-from-crypt-cpus" },
Packit 94f725
	{ CRYPT_ACTIVATE_NO_JOURNAL,             "no-journal" },
Packit 94f725
	{ 0, NULL }
Packit 94f725
};
Packit 94f725
Packit 94f725
int LUKS2_config_get_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *flags)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj_config, *jobj_flags;
Packit 94f725
	int i, j, found;
Packit 94f725
Packit 94f725
	if (!hdr || !flags)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	*flags = 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_config, "flags", &jobj_flags))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	for (i = 0; i < (int) json_object_array_length(jobj_flags); i++) {
Packit 94f725
		jobj1 = json_object_array_get_idx(jobj_flags, i);
Packit 94f725
		found = 0;
Packit 94f725
		for (j = 0; persistent_flags[j].description && !found; j++)
Packit 94f725
			if (!strcmp(persistent_flags[j].description,
Packit 94f725
				    json_object_get_string(jobj1))) {
Packit 94f725
				*flags |= persistent_flags[j].flag;
Packit 94f725
				log_dbg(cd, "Using persistent flag %s.",
Packit 94f725
					json_object_get_string(jobj1));
Packit 94f725
				found = 1;
Packit 94f725
			}
Packit 94f725
		if (!found)
Packit 94f725
			log_verbose(cd, _("Ignored unknown flag %s."),
Packit 94f725
				    json_object_get_string(jobj1));
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t flags)
Packit 94f725
{
Packit 94f725
	json_object *jobj_config, *jobj_flags;
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	jobj_flags = json_object_new_array();
Packit 94f725
Packit 94f725
	for (i = 0; persistent_flags[i].description; i++) {
Packit 94f725
		if (flags & persistent_flags[i].flag) {
Packit 94f725
			log_dbg(cd, "Setting persistent flag: %s.", persistent_flags[i].description);
Packit 94f725
			json_object_array_add(jobj_flags,
Packit 94f725
				json_object_new_string(persistent_flags[i].description));
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* Replace or add new flags array */
Packit 94f725
	json_object_object_add(jobj_config, "flags", jobj_flags);
Packit 94f725
Packit 94f725
	return LUKS2_hdr_write(cd, hdr);
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * json format example (mandatory array must not be ignored,
Packit 94f725
 * all other future fields may be added later)
Packit 94f725
 *
Packit 94f725
 * "requirements": {
Packit 94f725
 *       mandatory : [],
Packit 94f725
 *       optional0 : [],
Packit 94f725
 *       optional1 : "lala"
Packit 94f725
 * }
Packit 94f725
 */
Packit 94f725
Packit 94f725
/* LUKS2 library requirements */
Packit 94f725
static const struct  {
Packit 94f725
	uint32_t flag;
Packit 94f725
	const char *description;
Packit 94f725
} requirements_flags[] = {
Packit 94f725
	{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" },
Packit 94f725
	{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" },
Packit 94f725
	{ 0, NULL }
Packit 94f725
};
Packit 94f725
Packit 94f725
static uint32_t get_requirement_by_name(const char *requirement)
Packit 94f725
{
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	for (i = 0; requirements_flags[i].description; i++)
Packit 94f725
		if (!strcmp(requirement, requirements_flags[i].description))
Packit 94f725
			return requirements_flags[i].flag;
Packit 94f725
Packit 94f725
	return CRYPT_REQUIREMENT_UNKNOWN;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * returns count of requirements (past cryptsetup 2.0 release)
Packit 94f725
 */
Packit 94f725
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs)
Packit 94f725
{
Packit 94f725
	json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
Packit 94f725
	int i, len;
Packit 94f725
	uint32_t req;
Packit 94f725
Packit 94f725
	assert(hdr);
Packit 94f725
	if (!hdr || !reqs)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	*reqs = 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	len = (int) json_object_array_length(jobj_mandatory);
Packit 94f725
	if (len <= 0)
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	log_dbg(cd, "LUKS2 requirements detected:");
Packit 94f725
Packit 94f725
	for (i = 0; i < len; i++) {
Packit 94f725
		jobj = json_object_array_get_idx(jobj_mandatory, i);
Packit 94f725
		req = get_requirement_by_name(json_object_get_string(jobj));
Packit 94f725
		log_dbg(cd, "%s - %sknown", json_object_get_string(jobj),
Packit 94f725
				        reqs_unknown(req) ? "un" : "");
Packit 94f725
		*reqs |= req;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit)
Packit 94f725
{
Packit 94f725
	json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj;
Packit 94f725
	int i, r = -EINVAL;
Packit 94f725
Packit 94f725
	if (!hdr)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	jobj_mandatory = json_object_new_array();
Packit 94f725
	if (!jobj_mandatory)
Packit 94f725
		return -ENOMEM;
Packit 94f725
Packit 94f725
	for (i = 0; requirements_flags[i].description; i++) {
Packit 94f725
		if (reqs & requirements_flags[i].flag) {
Packit 94f725
			jobj = json_object_new_string(requirements_flags[i].description);
Packit 94f725
			if (!jobj) {
Packit 94f725
				r = -ENOMEM;
Packit 94f725
				goto err;
Packit 94f725
			}
Packit 94f725
			json_object_array_add(jobj_mandatory, jobj);
Packit 94f725
			/* erase processed flag from input set */
Packit 94f725
			reqs &= ~(requirements_flags[i].flag);
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* any remaining bit in requirements is unknown therefore illegal */
Packit 94f725
	if (reqs) {
Packit 94f725
		log_dbg(cd, "Illegal requirement flag(s) requested");
Packit 94f725
		goto err;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
Packit 94f725
		goto err;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) {
Packit 94f725
		jobj_requirements = json_object_new_object();
Packit 94f725
		if (!jobj_requirements) {
Packit 94f725
			r = -ENOMEM;
Packit 94f725
			goto err;
Packit 94f725
		}
Packit 94f725
		json_object_object_add(jobj_config, "requirements", jobj_requirements);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (json_object_array_length(jobj_mandatory) > 0) {
Packit 94f725
		/* replace mandatory field with new values */
Packit 94f725
		json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory);
Packit 94f725
	} else {
Packit 94f725
		/* new mandatory field was empty, delete old one */
Packit 94f725
		json_object_object_del(jobj_requirements, "mandatory");
Packit 94f725
		json_object_put(jobj_mandatory);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* remove empty requirements object */
Packit 94f725
	if (!json_object_object_length(jobj_requirements))
Packit 94f725
		json_object_object_del(jobj_config, "requirements");
Packit 94f725
Packit 94f725
	return commit ? LUKS2_hdr_write(cd, hdr) : 0;
Packit 94f725
err:
Packit 94f725
	json_object_put(jobj_mandatory);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * Header dump
Packit 94f725
 */
Packit 94f725
static void hdr_dump_config(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
Packit 94f725
	json_object *jobj1, *jobj_config, *jobj_flags, *jobj_requirements, *jobj_mandatory;
Packit 94f725
	int i = 0, flags = 0, reqs = 0;
Packit 94f725
Packit 94f725
	log_std(cd, "Flags:       \t");
Packit 94f725
Packit 94f725
	if (json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) {
Packit 94f725
		if (json_object_object_get_ex(jobj_config, "flags", &jobj_flags))
Packit 94f725
			flags = (int) json_object_array_length(jobj_flags);
Packit 94f725
		if (json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements) &&
Packit 94f725
		    json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory))
Packit 94f725
			reqs = (int) json_object_array_length(jobj_mandatory);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	for (i = 0; i < flags; i++) {
Packit 94f725
		jobj1 = json_object_array_get_idx(jobj_flags, i);
Packit 94f725
		log_std(cd, "%s ", json_object_get_string(jobj1));
Packit 94f725
	}
Packit 94f725
Packit 94f725
	log_std(cd, "%s\n%s", flags > 0 ? "" : "(no flags)", reqs > 0 ? "" : "\n");
Packit 94f725
Packit 94f725
	if (reqs > 0) {
Packit 94f725
		log_std(cd, "Requirements:\t");
Packit 94f725
		for (i = 0; i < reqs; i++) {
Packit 94f725
			jobj1 = json_object_array_get_idx(jobj_mandatory, i);
Packit 94f725
			log_std(cd, "%s ", json_object_get_string(jobj1));
Packit 94f725
		}
Packit 94f725
		log_std(cd, "\n\n");
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
static const char *get_priority_desc(json_object *jobj)
Packit 94f725
{
Packit 94f725
	crypt_keyslot_priority priority;
Packit 94f725
	json_object *jobj_priority;
Packit 94f725
	const char *text;
Packit 94f725
Packit 94f725
	if (json_object_object_get_ex(jobj, "priority", &jobj_priority))
Packit 94f725
		priority = (crypt_keyslot_priority)(int)json_object_get_int(jobj_priority);
Packit 94f725
	else
Packit 94f725
		priority = CRYPT_SLOT_PRIORITY_NORMAL;
Packit 94f725
Packit 94f725
	switch (priority) {
Packit 94f725
		case CRYPT_SLOT_PRIORITY_IGNORE: text = "ignored"; break;
Packit 94f725
		case CRYPT_SLOT_PRIORITY_PREFER: text = "preferred"; break;
Packit 94f725
		case CRYPT_SLOT_PRIORITY_NORMAL: text = "normal"; break;
Packit 94f725
		default: text = "invalid";
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return text;
Packit 94f725
}
Packit 94f725
Packit 94f725
static void hdr_dump_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	char slot[16];
Packit 94f725
	json_object *keyslots_jobj, *digests_jobj, *jobj2, *jobj3, *val;
Packit 94f725
	const char *tmps;
Packit 94f725
	int i, j, r;
Packit 94f725
Packit 94f725
	log_std(cd, "Keyslots:\n");
Packit 94f725
	json_object_object_get_ex(hdr_jobj, "keyslots", &keyslots_jobj);
Packit 94f725
Packit 94f725
	for (j = 0; j < LUKS2_KEYSLOTS_MAX; j++) {
Packit 94f725
		(void) snprintf(slot, sizeof(slot), "%i", j);
Packit 94f725
		json_object_object_get_ex(keyslots_jobj, slot, &val;;
Packit 94f725
		if (!val)
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		json_object_object_get_ex(val, "type", &jobj2);
Packit 94f725
		tmps = json_object_get_string(jobj2);
Packit 94f725
Packit 94f725
		r = LUKS2_keyslot_for_segment(crypt_get_hdr(cd, CRYPT_LUKS2), j, CRYPT_ONE_SEGMENT);
Packit 94f725
		log_std(cd, "  %s: %s%s\n", slot, tmps, r == -ENOENT ? " (unbound)" : "");
Packit 94f725
Packit 94f725
		if (json_object_object_get_ex(val, "key_size", &jobj2))
Packit 94f725
			log_std(cd, "\tKey:        %u bits\n", crypt_jobj_get_uint32(jobj2) * 8);
Packit 94f725
Packit 94f725
		log_std(cd, "\tPriority:   %s\n", get_priority_desc(val));
Packit 94f725
Packit 94f725
		LUKS2_keyslot_dump(cd, j);
Packit 94f725
Packit 94f725
		json_object_object_get_ex(hdr_jobj, "digests", &digests_jobj);
Packit 94f725
		json_object_object_foreach(digests_jobj, key2, val2) {
Packit 94f725
			json_object_object_get_ex(val2, "keyslots", &jobj2);
Packit 94f725
			for (i = 0; i < (int) json_object_array_length(jobj2); i++) {
Packit 94f725
				jobj3 = json_object_array_get_idx(jobj2, i);
Packit 94f725
				if (!strcmp(slot, json_object_get_string(jobj3))) {
Packit 94f725
					log_std(cd, "\tDigest ID:  %s\n", key2);
Packit 94f725
				}
Packit 94f725
			}
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
static void hdr_dump_tokens(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	char token[16];
Packit 94f725
	json_object *tokens_jobj, *jobj2, *jobj3, *val;
Packit 94f725
	const char *tmps;
Packit 94f725
	int i, j;
Packit 94f725
Packit 94f725
	log_std(cd, "Tokens:\n");
Packit 94f725
	json_object_object_get_ex(hdr_jobj, "tokens", &tokens_jobj);
Packit 94f725
Packit 94f725
	for (j = 0; j < LUKS2_TOKENS_MAX; j++) {
Packit 94f725
		(void) snprintf(token, sizeof(token), "%i", j);
Packit 94f725
		json_object_object_get_ex(tokens_jobj, token, &val;;
Packit 94f725
		if (!val)
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		json_object_object_get_ex(val, "type", &jobj2);
Packit 94f725
		tmps = json_object_get_string(jobj2);
Packit 94f725
		log_std(cd, "  %s: %s\n", token, tmps);
Packit 94f725
Packit 94f725
		LUKS2_token_dump(cd, j);
Packit 94f725
Packit 94f725
		json_object_object_get_ex(val, "keyslots", &jobj2);
Packit 94f725
		for (i = 0; i < (int) json_object_array_length(jobj2); i++) {
Packit 94f725
			jobj3 = json_object_array_get_idx(jobj2, i);
Packit 94f725
			log_std(cd, "\tKeyslot:  %s\n", json_object_get_string(jobj3));
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
static void hdr_dump_segments(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	char segment[16];
Packit 94f725
	json_object *jobj_segments, *jobj_segment, *jobj1, *jobj2;
Packit 94f725
	int i, j, flags;
Packit 94f725
	uint64_t value;
Packit 94f725
Packit 94f725
	log_std(cd, "Data segments:\n");
Packit 94f725
	json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments);
Packit 94f725
Packit 94f725
	for (i = 0; i < LUKS2_SEGMENT_MAX; i++) {
Packit 94f725
		(void) snprintf(segment, sizeof(segment), "%i", i);
Packit 94f725
		if (!json_object_object_get_ex(jobj_segments, segment, &jobj_segment))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		json_object_object_get_ex(jobj_segment, "type", &jobj1);
Packit 94f725
		log_std(cd, "  %s: %s\n", segment, json_object_get_string(jobj1));
Packit 94f725
Packit 94f725
		json_object_object_get_ex(jobj_segment, "offset", &jobj1);
Packit 94f725
		json_str_to_uint64(jobj1, &value);
Packit 94f725
		log_std(cd, "\toffset: %" PRIu64 " [bytes]\n", value);
Packit 94f725
Packit 94f725
		json_object_object_get_ex(jobj_segment, "size", &jobj1);
Packit 94f725
		if (!(strcmp(json_object_get_string(jobj1), "dynamic")))
Packit 94f725
			log_std(cd, "\tlength: (whole device)\n");
Packit 94f725
		else {
Packit 94f725
			json_str_to_uint64(jobj1, &value);
Packit 94f725
			log_std(cd, "\tlength: %" PRIu64 " [bytes]\n", value);
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (json_object_object_get_ex(jobj_segment, "encryption", &jobj1))
Packit 94f725
			log_std(cd, "\tcipher: %s\n", json_object_get_string(jobj1));
Packit 94f725
Packit 94f725
		if (json_object_object_get_ex(jobj_segment, "sector_size", &jobj1))
Packit 94f725
			log_std(cd, "\tsector: %" PRIu32 " [bytes]\n", crypt_jobj_get_uint32(jobj1));
Packit 94f725
Packit 94f725
		if (json_object_object_get_ex(jobj_segment, "integrity", &jobj1) &&
Packit 94f725
		    json_object_object_get_ex(jobj1, "type", &jobj2))
Packit 94f725
			log_std(cd, "\tintegrity: %s\n", json_object_get_string(jobj2));
Packit 94f725
Packit 94f725
		if (json_object_object_get_ex(jobj_segment, "flags", &jobj1) &&
Packit 94f725
		    (flags = (int)json_object_array_length(jobj1)) > 0) {
Packit 94f725
			jobj2 = json_object_array_get_idx(jobj1, 0);
Packit 94f725
			log_std(cd, "\tflags : %s", json_object_get_string(jobj2));
Packit 94f725
			for (j = 1; j < flags; j++) {
Packit 94f725
				jobj2 = json_object_array_get_idx(jobj1, j);
Packit 94f725
				log_std(cd, ", %s", json_object_get_string(jobj2));
Packit 94f725
			}
Packit 94f725
			log_std(cd, "\n");
Packit 94f725
		}
Packit 94f725
Packit 94f725
		log_std(cd, "\n");
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
static void hdr_dump_digests(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	char key[16];
Packit 94f725
	json_object *jobj1, *jobj2, *val;
Packit 94f725
	const char *tmps;
Packit 94f725
	int i;
Packit 94f725
Packit 94f725
	log_std(cd, "Digests:\n");
Packit 94f725
	json_object_object_get_ex(hdr_jobj, "digests", &jobj1);
Packit 94f725
Packit 94f725
	for (i = 0; i < LUKS2_DIGEST_MAX; i++) {
Packit 94f725
		(void) snprintf(key, sizeof(key), "%i", i);
Packit 94f725
		json_object_object_get_ex(jobj1, key, &val;;
Packit 94f725
		if (!val)
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		json_object_object_get_ex(val, "type", &jobj2);
Packit 94f725
		tmps = json_object_get_string(jobj2);
Packit 94f725
		log_std(cd, "  %s: %s\n", key, tmps);
Packit 94f725
Packit 94f725
		LUKS2_digest_dump(cd, i);
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	if (!hdr->jobj)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	JSON_DBG(cd, hdr->jobj, NULL);
Packit 94f725
Packit 94f725
	log_std(cd, "LUKS header information\n");
Packit 94f725
	log_std(cd, "Version:       \t%u\n", hdr->version);
Packit 94f725
	log_std(cd, "Epoch:         \t%" PRIu64 "\n", hdr->seqid);
Packit 94f725
	log_std(cd, "Metadata area: \t%" PRIu64 " [bytes]\n", LUKS2_metadata_size(hdr->jobj));
Packit 94f725
	log_std(cd, "Keyslots area: \t%" PRIu64 " [bytes]\n", LUKS2_keyslots_size(hdr->jobj));
Packit 94f725
	log_std(cd, "UUID:          \t%s\n", *hdr->uuid ? hdr->uuid : "(no UUID)");
Packit 94f725
	log_std(cd, "Label:         \t%s\n", *hdr->label ? hdr->label : "(no label)");
Packit 94f725
	log_std(cd, "Subsystem:     \t%s\n", *hdr->subsystem ? hdr->subsystem : "(no subsystem)");
Packit 94f725
Packit 94f725
	hdr_dump_config(cd, hdr->jobj);
Packit 94f725
	hdr_dump_segments(cd, hdr->jobj);
Packit 94f725
	hdr_dump_keyslots(cd, hdr->jobj);
Packit 94f725
	hdr_dump_tokens(cd, hdr->jobj);
Packit 94f725
	hdr_dump_digests(cd, hdr->jobj);
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic)
Packit 94f725
{
Packit 94f725
	int sector_size;
Packit 94f725
	json_object *jobj_segments, *jobj_size;
Packit 94f725
	uint64_t tmp = 0;
Packit 94f725
Packit 94f725
	if (!size || !json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, key, val) {
Packit 94f725
		UNUSED(key);
Packit 94f725
		if (json_segment_is_backup(val))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		json_object_object_get_ex(val, "size", &jobj_size);
Packit 94f725
		if (!strcmp(json_object_get_string(jobj_size), "dynamic")) {
Packit 94f725
			sector_size = json_segment_get_sector_size(val);
Packit 94f725
			/* last dynamic segment must have at least one sector in size */
Packit 94f725
			if (tmp)
Packit 94f725
				*size = tmp + (sector_size > 0 ? sector_size : SECTOR_SIZE);
Packit 94f725
			else
Packit 94f725
				*size = 0;
Packit 94f725
			if (dynamic)
Packit 94f725
				*dynamic = true;
Packit 94f725
			return 0;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		tmp += crypt_jobj_get_uint64(jobj_size);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* impossible, real device size must not be zero */
Packit 94f725
	if (!tmp)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	*size = tmp;
Packit 94f725
	if (dynamic)
Packit 94f725
		*dynamic = false;
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	crypt_reencrypt_info ri;
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	ri = LUKS2_reenc_status(hdr);
Packit 94f725
	if (ri == CRYPT_REENCRYPT_CLEAN || ri == CRYPT_REENCRYPT_CRASH) {
Packit 94f725
		jobj = LUKS2_get_segment_by_flag(hdr, "backup-final");
Packit 94f725
		if (jobj)
Packit 94f725
			return json_segment_get_offset(jobj, 1);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return json_segments_get_minimal_offset(LUKS2_get_segments_jobj(hdr), 1);
Packit 94f725
}
Packit 94f725
Packit 94f725
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segment;
Packit 94f725
Packit 94f725
	if (!hdr)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (segment == CRYPT_DEFAULT_SEGMENT)
Packit 94f725
		segment = LUKS2_get_default_segment(hdr);
Packit 94f725
Packit 94f725
	jobj_segment = json_segments_get_segment(json_get_segments_jobj(hdr->jobj), segment);
Packit 94f725
	if (!jobj_segment)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	/* FIXME: default encryption (for other segment types) must be string here. */
Packit 94f725
	return json_segment_get_cipher(jobj_segment) ?: "null";
Packit 94f725
}
Packit 94f725
Packit 94f725
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	uint32_t reqs;
Packit 94f725
Packit 94f725
	/*
Packit 94f725
	 * Any unknown requirement or offline reencryption should abort
Packit 94f725
	 * anything related to online-reencryption handling
Packit 94f725
	 */
Packit 94f725
	if (LUKS2_config_get_requirements(NULL, hdr, &reqs))
Packit 94f725
		return CRYPT_REENCRYPT_INVALID;
Packit 94f725
Packit 94f725
	if (!reqs_reencrypt_online(reqs))
Packit 94f725
		return CRYPT_REENCRYPT_NONE;
Packit 94f725
Packit 94f725
	if (json_segments_segment_in_reencrypt(LUKS2_get_segments_jobj(hdr)) < 0)
Packit 94f725
		return CRYPT_REENCRYPT_CLEAN;
Packit 94f725
Packit 94f725
	return CRYPT_REENCRYPT_CRASH;
Packit 94f725
}
Packit 94f725
Packit 94f725
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size)
Packit 94f725
{
Packit 94f725
	json_object *jobj_keyslot, *jobj_area, *jobj1;
Packit 94f725
Packit 94f725
	jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
Packit 94f725
	if (!jobj_keyslot)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	/* currently we only support raw length preserving area encryption */
Packit 94f725
	json_object_object_get_ex(jobj_area, "type", &jobj1);
Packit 94f725
	if (strcmp(json_object_get_string(jobj1), "raw"))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_area, "key_size", &jobj1))
Packit 94f725
		return NULL;
Packit 94f725
	*key_size = json_object_get_int(jobj1);
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_area, "encryption", &jobj1))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return json_object_get_string(jobj1);
Packit 94f725
}
Packit 94f725
Packit 94f725
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2, *jobj3;
Packit 94f725
Packit 94f725
	jobj1 = LUKS2_get_segment_jobj(hdr, segment);
Packit 94f725
	if (!jobj1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj1, "integrity", &jobj2))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj2, "type", &jobj3))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return json_object_get_string(jobj3);
Packit 94f725
}
Packit 94f725
Packit 94f725
/* FIXME: this only ensures that once we have journal encryption, it is not ignored. */
Packit 94f725
/* implement segment count and type restrictions (crypt and only single crypt) */
Packit 94f725
static int LUKS2_integrity_compatible(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2, *jobj3, *jobj4;
Packit 94f725
	const char *str;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj1))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!(jobj2 = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT)))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj2, "integrity", &jobj3))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj3, "journal_encryption", &jobj4) ||
Packit 94f725
	    !(str = json_object_get_string(jobj4)) ||
Packit 94f725
	    strcmp(str, "none"))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj3, "journal_integrity", &jobj4) ||
Packit 94f725
	    !(str = json_object_get_string(jobj4)) ||
Packit 94f725
	    strcmp(str, "none"))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	return 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
static int LUKS2_keyslot_get_volume_key_size(struct luks2_hdr *hdr, const char *keyslot)
Packit 94f725
{
Packit 94f725
	json_object *jobj1, *jobj2, *jobj3;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj1))
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj1, keyslot, &jobj2))
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj2, "key_size", &jobj3))
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	return json_object_get_int(jobj3);
Packit 94f725
}
Packit 94f725
Packit 94f725
/* Key size used for encryption of keyslot */
Packit 94f725
int LUKS2_get_keyslot_stored_key_size(struct luks2_hdr *hdr, int keyslot)
Packit 94f725
{
Packit 94f725
	char keyslot_name[16];
Packit 94f725
Packit 94f725
	if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	return LUKS2_keyslot_get_volume_key_size(hdr, keyslot_name);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj_digests, *jobj_digest_segments, *jobj_digest_keyslots, *jobj1;
Packit 94f725
	char buf[16];
Packit 94f725
Packit 94f725
	if (segment == CRYPT_DEFAULT_SEGMENT)
Packit 94f725
		segment = LUKS2_get_default_segment(hdr);
Packit 94f725
Packit 94f725
	if (snprintf(buf, sizeof(buf), "%u", segment) < 1)
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_digests, key, val) {
Packit 94f725
		UNUSED(key);
Packit 94f725
		json_object_object_get_ex(val, "segments", &jobj_digest_segments);
Packit 94f725
		json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
Packit 94f725
Packit 94f725
		if (!LUKS2_array_jobj(jobj_digest_segments, buf))
Packit 94f725
			continue;
Packit 94f725
		if (json_object_array_length(jobj_digest_keyslots) <= 0)
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		jobj1 = json_object_array_get_idx(jobj_digest_keyslots, 0);
Packit 94f725
Packit 94f725
		return LUKS2_keyslot_get_volume_key_size(hdr, json_object_get_string(jobj1));
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return -1;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_get_sector_size(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segment;
Packit 94f725
Packit 94f725
	jobj_segment = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT);
Packit 94f725
	if (!jobj_segment)
Packit 94f725
		return SECTOR_SIZE;
Packit 94f725
Packit 94f725
	return json_segment_get_sector_size(jobj_segment) ?: SECTOR_SIZE;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd,
Packit 94f725
	struct luks2_hdr *hdr,
Packit 94f725
	struct volume_key *vks,
Packit 94f725
	json_object *jobj_segments,
Packit 94f725
	struct crypt_dm_active_device *dmd)
Packit 94f725
{
Packit 94f725
	struct volume_key *vk;
Packit 94f725
	json_object *jobj;
Packit 94f725
	enum devcheck device_check;
Packit 94f725
	int r;
Packit 94f725
	unsigned s = 0;
Packit 94f725
	uint64_t data_offset, segment_size, segment_offset, segment_start = 0;
Packit 94f725
	struct dm_target *t = &dmd->segment;
Packit 94f725
Packit 94f725
	if (dmd->flags & CRYPT_ACTIVATE_SHARED)
Packit 94f725
		device_check = DEV_OK;
Packit 94f725
	else
Packit 94f725
		device_check = DEV_EXCL;
Packit 94f725
Packit 94f725
	data_offset = LUKS2_reencrypt_data_offset(hdr, true);
Packit 94f725
Packit 94f725
	r = device_block_adjust(cd, crypt_data_device(cd), device_check,
Packit 94f725
			                                data_offset, &dmd->size, &dmd->flags);
Packit 94f725
	if (r)
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	r = dm_targets_allocate(&dmd->segment, json_segments_count(jobj_segments));
Packit 94f725
	if (r)
Packit 94f725
		goto err;
Packit 94f725
Packit 94f725
	r = -EINVAL;
Packit 94f725
Packit 94f725
	while (t) {
Packit 94f725
		jobj = json_segments_get_segment(jobj_segments, s);
Packit 94f725
		if (!jobj) {
Packit 94f725
			log_dbg(cd, "Internal error. Segment %u is null.", s);
Packit 94f725
			r = -EINVAL;
Packit 94f725
			goto err;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		segment_offset = json_segment_get_offset(jobj, 1);
Packit 94f725
		segment_size = json_segment_get_size(jobj, 1);
Packit 94f725
		/* 'dynamic' length allowed in last segment only */
Packit 94f725
		if (!segment_size && !t->next)
Packit 94f725
			segment_size = dmd->size - segment_start;
Packit 94f725
		if (!segment_size) {
Packit 94f725
			log_dbg(cd, "Internal error. Wrong segment size %u", s);
Packit 94f725
			r = -EINVAL;
Packit 94f725
			goto err;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (!strcmp(json_segment_type(jobj), "crypt")) {
Packit 94f725
			vk = crypt_volume_key_by_id(vks, LUKS2_digest_by_segment(hdr, s));
Packit 94f725
			if (!vk) {
Packit 94f725
				log_err(cd, _("Missing key for dm-crypt segment %u"), s);
Packit 94f725
				r = -EINVAL;
Packit 94f725
				goto err;
Packit 94f725
			}
Packit 94f725
Packit 94f725
			r = dm_crypt_target_set(t, segment_start, segment_size,
Packit 94f725
					crypt_data_device(cd), vk,
Packit 94f725
					json_segment_get_cipher(jobj),
Packit 94f725
					json_segment_get_iv_offset(jobj),
Packit 94f725
					segment_offset, "none", 0,
Packit 94f725
					json_segment_get_sector_size(jobj));
Packit 94f725
			if (r) {
Packit 94f725
				log_err(cd, _("Failed to set dm-crypt segment."));
Packit 94f725
				goto err;
Packit 94f725
			}
Packit 94f725
		} else if (!strcmp(json_segment_type(jobj), "linear")) {
Packit 94f725
			r = dm_linear_target_set(t, segment_start, segment_size, crypt_data_device(cd), segment_offset);
Packit 94f725
			if (r) {
Packit 94f725
				log_err(cd, _("Failed to set dm-linear segment."));
Packit 94f725
				goto err;
Packit 94f725
			}
Packit 94f725
		} else {
Packit 94f725
			r = -EINVAL;
Packit 94f725
			goto err;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		segment_start += segment_size;
Packit 94f725
		t = t->next;
Packit 94f725
		s++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return r;
Packit 94f725
err:
Packit 94f725
	dm_targets_free(cd, dmd);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
/* FIXME: This shares almost all code with activate_multi_custom */
Packit 94f725
static int _reload_custom_multi(struct crypt_device *cd,
Packit 94f725
	const char *name,
Packit 94f725
	struct volume_key *vks,
Packit 94f725
	json_object *jobj_segments,
Packit 94f725
	uint64_t device_size,
Packit 94f725
	uint32_t flags)
Packit 94f725
{
Packit 94f725
	int r;
Packit 94f725
	struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
Packit 94f725
	struct crypt_dm_active_device dmd =  {
Packit 94f725
		.uuid   = crypt_get_uuid(cd),
Packit 94f725
		.size = device_size >> SECTOR_SHIFT
Packit 94f725
	};
Packit 94f725
Packit 94f725
	/* do not allow activation when particular requirements detected */
Packit 94f725
	if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0)))
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	/* Add persistent activation flags */
Packit 94f725
	if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
Packit 94f725
		LUKS2_config_get_flags(cd, hdr, &dmd.flags);
Packit 94f725
Packit 94f725
	dmd.flags |= (flags | CRYPT_ACTIVATE_SHARED);
Packit 94f725
Packit 94f725
	r = LUKS2_assembly_multisegment_dmd(cd, hdr, vks, jobj_segments, &dmd);
Packit 94f725
	if (!r)
Packit 94f725
		r = dm_reload_device(cd, name, &dmd, 0, 0);
Packit 94f725
Packit 94f725
	dm_targets_free(cd, &dmd);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_reload(struct crypt_device *cd,
Packit 94f725
	const char *name,
Packit 94f725
	struct volume_key *vks,
Packit 94f725
	uint64_t device_size,
Packit 94f725
	uint32_t flags)
Packit 94f725
{
Packit 94f725
	if (crypt_get_integrity_tag_size(cd))
Packit 94f725
		return -ENOTSUP;
Packit 94f725
Packit 94f725
	return _reload_custom_multi(cd, name, vks,
Packit 94f725
			LUKS2_get_segments_jobj(crypt_get_hdr(cd, CRYPT_LUKS2)), device_size, flags);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_activate_multi(struct crypt_device *cd,
Packit 94f725
	const char *name,
Packit 94f725
	struct volume_key *vks,
Packit 94f725
	uint64_t device_size,
Packit 94f725
	uint32_t flags)
Packit 94f725
{
Packit 94f725
	struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
Packit 94f725
	json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
Packit 94f725
	int r;
Packit 94f725
	struct crypt_dm_active_device dmd = {
Packit 94f725
		.size	= device_size,
Packit 94f725
		.uuid   = crypt_get_uuid(cd)
Packit 94f725
	};
Packit 94f725
Packit 94f725
	/* do not allow activation when particular requirements detected */
Packit 94f725
	if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0)))
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	/* Add persistent activation flags */
Packit 94f725
	if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
Packit 94f725
		LUKS2_config_get_flags(cd, hdr, &dmd.flags);
Packit 94f725
Packit 94f725
	dmd.flags |= flags;
Packit 94f725
Packit 94f725
	r = LUKS2_assembly_multisegment_dmd(cd, hdr, vks, jobj_segments, &dmd);
Packit 94f725
	if (!r)
Packit 94f725
		r = dm_create_device(cd, name, CRYPT_LUKS2, &dmd);
Packit 94f725
Packit 94f725
	dm_targets_free(cd, &dmd);
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_activate(struct crypt_device *cd,
Packit 94f725
	const char *name,
Packit 94f725
	struct volume_key *vk,
Packit 94f725
	uint32_t flags)
Packit 94f725
{
Packit 94f725
	int r;
Packit 94f725
	struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
Packit 94f725
	struct crypt_dm_active_device dmdi = {}, dmd = {
Packit 94f725
		.uuid   = crypt_get_uuid(cd)
Packit 94f725
	};
Packit 94f725
Packit 94f725
	/* do not allow activation when particular requirements detected */
Packit 94f725
	if ((r = LUKS2_unmet_requirements(cd, hdr, 0, 0)))
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
Packit 94f725
			vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd),
Packit 94f725
			crypt_get_data_offset(cd), crypt_get_integrity(cd) ?: "none",
Packit 94f725
			crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd));
Packit 94f725
	if (r < 0)
Packit 94f725
		return r;
Packit 94f725
Packit 94f725
	/* Add persistent activation flags */
Packit 94f725
	if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
Packit 94f725
		LUKS2_config_get_flags(cd, hdr, &dmd.flags);
Packit 94f725
Packit 94f725
	dmd.flags |= flags;
Packit 94f725
Packit 94f725
	if (crypt_get_integrity_tag_size(cd)) {
Packit 94f725
		if (!LUKS2_integrity_compatible(hdr)) {
Packit 94f725
			log_err(cd, _("Unsupported device integrity configuration."));
Packit 94f725
			return -EINVAL;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		if (dmd.flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) {
Packit 94f725
			log_err(cd, _("Discard/TRIM is not supported."));
Packit 94f725
			return -EINVAL;
Packit 94f725
		}
Packit 94f725
Packit 94f725
		r = INTEGRITY_create_dmd_device(cd, NULL, NULL, NULL, NULL, &dmdi, dmd.flags, 0);
Packit 94f725
		if (r)
Packit 94f725
			return r;
Packit 94f725
Packit 94f725
		dmdi.flags |= CRYPT_ACTIVATE_PRIVATE;
Packit 94f725
		dmdi.uuid = dmd.uuid;
Packit 94f725
		dmd.segment.u.crypt.offset = 0;
Packit 94f725
		dmd.segment.size = dmdi.segment.size;
Packit 94f725
Packit 94f725
		r = create_or_reload_device_with_integrity(cd, name, CRYPT_LUKS2, &dmd, &dmdi);
Packit 94f725
	} else
Packit 94f725
		r = create_or_reload_device(cd, name, CRYPT_LUKS2, &dmd);
Packit 94f725
Packit 94f725
	dm_targets_free(cd, &dmd);
Packit 94f725
	dm_targets_free(cd, &dmdi);
Packit 94f725
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
static bool is_reencryption_helper(const char *name)
Packit 94f725
{
Packit 94f725
	size_t len;
Packit 94f725
Packit 94f725
	if (!name)
Packit 94f725
		return false;
Packit 94f725
Packit 94f725
	len = strlen(name);
Packit 94f725
	return (len >= 9 && (!strncmp(name + len - 8, "-hotzone-", 9) ||
Packit 94f725
			     !strcmp(name + len - 8, "-overlay")));
Packit 94f725
Packit 94f725
}
Packit 94f725
Packit 94f725
static bool contains_reencryption_helper(char **names)
Packit 94f725
{
Packit 94f725
	while (*names) {
Packit 94f725
		if (is_reencryption_helper(*names++))
Packit 94f725
			return true;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return false;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr *hdr, struct crypt_dm_active_device *dmd, uint32_t flags)
Packit 94f725
{
Packit 94f725
	int r, ret;
Packit 94f725
	struct dm_target *tgt;
Packit 94f725
	crypt_status_info ci;
Packit 94f725
	struct crypt_dm_active_device dmdc;
Packit 94f725
	char **dep, deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = { 0 };
Packit 94f725
	const char *namei = NULL;
Packit 94f725
	struct crypt_lock_handle *reencrypt_lock = NULL;
Packit 94f725
Packit 94f725
	if (!dmd || !dmd->uuid || strncmp(CRYPT_LUKS2, dmd->uuid, sizeof(CRYPT_LUKS2)-1))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	/* uuid mismatch with metadata (if available) */
Packit 94f725
	if (hdr && crypt_uuid_cmp(dmd->uuid, hdr->uuid))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), CRYPT_SUBDEV "-%.32s", dmd->uuid + 6);
Packit 94f725
	if (r < 0 || (size_t)r != (sizeof(deps_uuid_prefix) - 1))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	tgt = &dmd->segment;
Packit 94f725
Packit 94f725
	/* TODO: We have LUKS2 dependencies now */
Packit 94f725
	if (hdr && single_segment(dmd) && tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
Packit 94f725
		namei = device_dm_name(tgt->data_device);
Packit 94f725
Packit 94f725
	r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
Packit 94f725
	if (r < 0)
Packit 94f725
		goto out;
Packit 94f725
Packit 94f725
	if (contains_reencryption_helper(deps)) {
Packit 94f725
		r = crypt_reencrypt_lock_by_dm_uuid(cd, dmd->uuid, &reencrypt_lock);
Packit 94f725
		if (r) {
Packit 94f725
			if (r == -EBUSY)
Packit 94f725
				log_err(cd, _("Reencryption in-progress. Cannot deactivate device."));
Packit 94f725
			else
Packit 94f725
				log_err(cd, _("Failed to get reencryption lock."));
Packit 94f725
			goto out;
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
Packit 94f725
	dep = deps;
Packit 94f725
	while (*dep) {
Packit 94f725
		if (is_reencryption_helper(*dep) && (dm_status_suspended(cd, *dep) > 0)) {
Packit 94f725
			if (dm_error_device(cd, *dep))
Packit 94f725
				log_err(cd, _("Failed to replace suspended device %s with dm-error target."), *dep);
Packit 94f725
		}
Packit 94f725
		dep++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
Packit 94f725
	if (r < 0) {
Packit 94f725
		memset(&dmdc, 0, sizeof(dmdc));
Packit 94f725
		dmdc.segment.type = DM_UNKNOWN;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* Remove top level device first */
Packit 94f725
	r = dm_remove_device(cd, name, flags);
Packit 94f725
	if (!r) {
Packit 94f725
		tgt = &dmdc.segment;
Packit 94f725
		while (tgt) {
Packit 94f725
			if (tgt->type == DM_CRYPT)
Packit 94f725
				crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description, LOGON_KEY);
Packit 94f725
			tgt = tgt->next;
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
	dm_targets_free(cd, &dmdc);
Packit 94f725
Packit 94f725
	/* TODO: We have LUKS2 dependencies now */
Packit 94f725
	if (r >= 0 && namei) {
Packit 94f725
		log_dbg(cd, "Deactivating integrity device %s.", namei);
Packit 94f725
		r = dm_remove_device(cd, namei, 0);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (!r) {
Packit 94f725
		ret = 0;
Packit 94f725
		dep = deps;
Packit 94f725
		while (*dep) {
Packit 94f725
			log_dbg(cd, "Deactivating LUKS2 dependent device %s.", *dep);
Packit 94f725
			r = dm_query_device(cd, *dep, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
Packit 94f725
			if (r < 0) {
Packit 94f725
				memset(&dmdc, 0, sizeof(dmdc));
Packit 94f725
				dmdc.segment.type = DM_UNKNOWN;
Packit 94f725
			}
Packit 94f725
Packit 94f725
			r = dm_remove_device(cd, *dep, flags);
Packit 94f725
			if (r < 0) {
Packit 94f725
				ci = crypt_status(cd, *dep);
Packit 94f725
				if (ci == CRYPT_BUSY)
Packit 94f725
					log_err(cd, _("Device %s is still in use."), *dep);
Packit 94f725
				if (ci == CRYPT_INACTIVE)
Packit 94f725
					r = 0;
Packit 94f725
			}
Packit 94f725
			if (!r) {
Packit 94f725
				tgt = &dmdc.segment;
Packit 94f725
				while (tgt) {
Packit 94f725
					if (tgt->type == DM_CRYPT)
Packit 94f725
						crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description, LOGON_KEY);
Packit 94f725
					tgt = tgt->next;
Packit 94f725
				}
Packit 94f725
			}
Packit 94f725
			dm_targets_free(cd, &dmdc);
Packit 94f725
			if (r && !ret)
Packit 94f725
				ret = r;
Packit 94f725
			dep++;
Packit 94f725
		}
Packit 94f725
		r = ret;
Packit 94f725
	}
Packit 94f725
Packit 94f725
out:
Packit 94f725
	crypt_reencrypt_unlock(cd, reencrypt_lock);
Packit 94f725
	dep = deps;
Packit 94f725
	while (*dep)
Packit 94f725
		free(*dep++);
Packit 94f725
Packit 94f725
	return r;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet)
Packit 94f725
{
Packit 94f725
	uint32_t reqs;
Packit 94f725
	int r = LUKS2_config_get_requirements(cd, hdr, &reqs);
Packit 94f725
Packit 94f725
	if (r) {
Packit 94f725
		if (!quiet)
Packit 94f725
			log_err(cd, _("Failed to read LUKS2 requirements."));
Packit 94f725
		return r;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* do not mask unknown requirements check */
Packit 94f725
	if (reqs_unknown(reqs)) {
Packit 94f725
		if (!quiet)
Packit 94f725
			log_err(cd, _("Unmet LUKS2 requirements detected."));
Packit 94f725
		return -ETXTBSY;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	/* mask out permitted requirements */
Packit 94f725
	reqs &= ~reqs_mask;
Packit 94f725
Packit 94f725
	if (reqs_reencrypt(reqs) && !quiet)
Packit 94f725
		log_err(cd, _("Operation incompatible with device marked for legacy reencryption. Aborting."));
Packit 94f725
	if (reqs_reencrypt_online(reqs) && !quiet)
Packit 94f725
		log_err(cd, _("Operation incompatible with device marked for LUKS2 reencryption. Aborting."));
Packit 94f725
Packit 94f725
	/* any remaining unmasked requirement fails the check */
Packit 94f725
	return reqs ? -EINVAL : 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
/*
Packit 94f725
 * NOTE: this routine is called on json object that failed validation.
Packit 94f725
 * 	 Proceed with caution :)
Packit 94f725
 *
Packit 94f725
 * known glitches so far:
Packit 94f725
 *
Packit 94f725
 * any version < 2.0.3:
Packit 94f725
 *  - luks2 keyslot pbkdf params change via crypt_keyslot_change_by_passphrase()
Packit 94f725
 *    could leave previous type parameters behind. Correct this by purging
Packit 94f725
 *    all params not needed by current type.
Packit 94f725
 */
Packit 94f725
void LUKS2_hdr_repair(struct crypt_device *cd, json_object *hdr_jobj)
Packit 94f725
{
Packit 94f725
	json_object *jobj_keyslots;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots))
Packit 94f725
		return;
Packit 94f725
	if (!json_object_is_type(jobj_keyslots, json_type_object))
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	LUKS2_keyslots_repair(cd, jobj_keyslots);
Packit 94f725
}
Packit 94f725
Packit 94f725
void json_object_object_del_by_uint(json_object *jobj, unsigned key)
Packit 94f725
{
Packit 94f725
	char key_name[16];
Packit 94f725
Packit 94f725
	if (snprintf(key_name, sizeof(key_name), "%u", key) < 1)
Packit 94f725
		return;
Packit 94f725
	json_object_object_del(jobj, key_name);
Packit 94f725
}
Packit 94f725
Packit 94f725
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val)
Packit 94f725
{
Packit 94f725
	char key_name[16];
Packit 94f725
Packit 94f725
	if (snprintf(key_name, sizeof(key_name), "%u", key) < 1)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
#if HAVE_DECL_JSON_OBJECT_OBJECT_ADD_EX
Packit 94f725
	return json_object_object_add_ex(jobj, key_name, jobj_val, 0) ? -ENOMEM : 0;
Packit 94f725
#else
Packit 94f725
	json_object_object_add(jobj, key_name, jobj_val);
Packit 94f725
	return 0;
Packit 94f725
#endif
Packit 94f725
}
Packit 94f725
Packit 94f725
/* jobj_dst must contain pointer initialized to NULL (see json-c json_object_deep_copy API) */
Packit 94f725
int json_object_copy(json_object *jobj_src, json_object **jobj_dst)
Packit 94f725
{
Packit 94f725
	if (!jobj_src || !jobj_dst || *jobj_dst)
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
#if HAVE_DECL_JSON_OBJECT_DEEP_COPY
Packit 94f725
	return json_object_deep_copy(jobj_src, jobj_dst, NULL);
Packit 94f725
#else
Packit 94f725
	*jobj_dst = json_tokener_parse(json_object_get_string(jobj_src));
Packit 94f725
	return *jobj_dst ? 0 : -1;
Packit 94f725
#endif
Packit 94f725
}