Rewrite veritysetup to use libcryptsetup.

This commit is contained in:
Milan Broz
2012-06-07 00:18:49 +02:00
parent 850799802b
commit 4b0b82adc5
16 changed files with 1404 additions and 770 deletions

View File

@@ -351,6 +351,7 @@ lib/libcryptsetup.pc
lib/crypto_backend/Makefile
lib/luks1/Makefile
lib/loopaes/Makefile
lib/verity/Makefile
src/Makefile
po/Makefile.in
man/Makefile

View File

@@ -1,4 +1,4 @@
SUBDIRS = crypto_backend luks1 loopaes
SUBDIRS = crypto_backend luks1 loopaes verity
moduledir = $(libdir)/cryptsetup
@@ -10,6 +10,7 @@ INCLUDES = \
-I$(top_srcdir)/lib/crypto_backend \
-I$(top_srcdir)/lib/luks1 \
-I$(top_srcdir)/lib/loopaes \
-I$(top_srcdir)/lib/verity \
-DDATADIR=\""$(datadir)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DPREFIX=\""$(prefix)"\" \
@@ -24,7 +25,8 @@ lib_LTLIBRARIES = libcryptsetup.la
common_ldadd = \
crypto_backend/libcrypto_backend.la \
luks1/libluks1.la \
loopaes/libloopaes.la
loopaes/libloopaes.la \
verity/libverity.la
libcryptsetup_la_DEPENDENCIES = $(common_ldadd) libcryptsetup.sym

View File

@@ -38,6 +38,8 @@
#include "utils_fips.h"
#include "crypto_backend.h"
#include "libcryptsetup.h"
/* to silent gcc -Wcast-qual for const cast */
#define CONST_CAST(x) (x)(uintptr_t)

View File

@@ -301,6 +301,8 @@ int crypt_memory_lock(struct crypt_device *cd, int lock);
#define CRYPT_LUKS1 "LUKS1"
/** loop-AES compatibility mode */
#define CRYPT_LOOPAES "LOOPAES"
/** dm-verity mode */
#define CRYPT_VERITY "VERITY"
/**
* Get device type
@@ -351,6 +353,33 @@ struct crypt_params_loopaes {
uint64_t skip; /**< IV offset / initialization sector */
};
/**
*
* Structure used as parameter for dm-verity device type
*
* @see crypt_format, crypt_load
*
*/
/** No on-disk header (only hashes) */
#define CRYPT_VERITY_NO_HEADER (1 << 0)
/** Verity hash in userspace before activation */
#define CRYPT_VERITY_CHECK_HASH (1 << 1)
/** Create hash - format hash device */
#define CRYPT_VERITY_CREATE_HASH (1 << 2)
struct crypt_params_verity {
const char *hash_name; /**< hash function */
const char *data_device; /**< data_device (CRYPT_VERITY_CREATE_HASH) */
const char *salt; /**< salt */
uint64_t salt_size; /**< salt size (in bytes) */
uint32_t data_block_size; /**< data block size (in bytes) */
uint32_t hash_block_size; /**< hash block size (in bytes) */
uint64_t data_size; /**< data area size (in data blocks) */
uint64_t hash_area_offset; /**< hash/header offset (in bytes) */
uint32_t version; /**< in-kernel hash version */
uint32_t flags; /**< CRYPT_VERITY* flags */
};
/** @} */
/**

View File

@@ -28,12 +28,12 @@
#include <uuid/uuid.h>
#include "internal.h"
#include "luks.h"
#define DM_UUID_LEN 129
#define DM_UUID_PREFIX "CRYPT-"
#define DM_UUID_PREFIX_LEN 6
#define DM_CRYPT_TARGET "crypt"
#define DM_VERITY_TARGET "verity"
#define RETRY_COUNT 5
/* Set if dm-crypt version was probed */
@@ -241,7 +241,7 @@ static void hex_key(char *hexkey, size_t key_size, const char *key)
sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}
static char *get_params(struct crypt_dm_active_device *dmd)
static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd)
{
int r, max_size, null_cipher = 0;
char *params, *hexkey;
@@ -284,6 +284,47 @@ out:
crypt_safe_free(hexkey);
return params;
}
static char *get_dm_verity_params(struct crypt_params_verity *vp,
struct crypt_dm_active_verity *dmd)
{
int max_size, r;
char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
hexroot = crypt_safe_alloc(dmd->root_hash_size * 2 + 1);
if (!hexroot)
goto out;
hex_key(hexroot, dmd->root_hash_size, dmd->root_hash);
hexsalt = crypt_safe_alloc(vp->salt_size * 2 + 1);
if (!hexsalt)
goto out;
hex_key(hexsalt, vp->salt_size, vp->salt);
max_size = strlen(hexroot) + strlen(hexsalt) +
strlen(dmd->data_device) + strlen(dmd->hash_device) +
strlen(vp->hash_name) + 128;
params = crypt_safe_alloc(max_size);
if (!params)
goto out;
r = snprintf(params, max_size,
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s",
vp->version, dmd->data_device, dmd->hash_device,
vp->data_block_size, vp->hash_block_size,
vp->data_size, dmd->hash_offset,
vp->hash_name, hexroot, hexsalt);
if (r < 0 || r >= max_size) {
crypt_safe_free(params);
params = NULL;
}
log_dbg("TABLE: %s", params);
out:
crypt_safe_free(hexroot);
crypt_safe_free(hexsalt);
return params;
}
/* DM helpers */
static int _dm_simple(int task, const char *name, int udev_wait)
@@ -423,25 +464,20 @@ static void dm_prepare_uuid(const char *name, const char *type, const char *uuid
log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name);
}
int dm_create_device(const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
int reload)
static int _dm_create_device(const char *name, const char *type,
const char *device, uint32_t flags,
const char *uuid, uint64_t size,
char *params, int reload)
{
struct dm_task *dmt = NULL;
struct dm_info dmi;
char *params = NULL;
char dev_uuid[DM_UUID_LEN] = {0};
int r = -EINVAL;
uint32_t read_ahead = 0;
uint32_t cookie = 0;
uint16_t udev_flags = 0;
params = get_params(dmd);
if (!params)
goto out_no_removal;
if (dmd->flags & CRYPT_ACTIVATE_PRIVATE)
if (flags & CRYPT_ACTIVATE_PRIVATE)
udev_flags = CRYPT_TEMP_UDEV_FLAGS;
/* All devices must have DM_UUID, only resize on old device is exception */
@@ -452,7 +488,7 @@ int dm_create_device(const char *name,
if (!dm_task_set_name(dmt, name))
goto out_no_removal;
} else {
dm_prepare_uuid(name, type, dmd->uuid, dev_uuid, sizeof(dev_uuid));
dm_prepare_uuid(name, type, uuid, dev_uuid, sizeof(dev_uuid));
if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
goto out_no_removal;
@@ -469,13 +505,15 @@ int dm_create_device(const char *name,
if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
goto out_no_removal;
if ((dmd->flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
if ((flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
goto out_no_removal;
if (!dm_task_add_target(dmt, 0, dmd->size, DM_CRYPT_TARGET, params))
if (!dm_task_add_target(dmt, 0, size,
!strcmp("VERITY", type) ? DM_VERITY_TARGET : DM_CRYPT_TARGET, params))
goto out_no_removal;
#ifdef DM_READ_AHEAD_MINIMUM_FLAG
if (device_read_ahead(dmd->device, &read_ahead) &&
if (device_read_ahead(device, &read_ahead) &&
!dm_task_set_read_ahead(dmt, read_ahead, DM_READ_AHEAD_MINIMUM_FLAG))
goto out_no_removal;
#endif
@@ -489,7 +527,7 @@ int dm_create_device(const char *name,
goto out;
if (!dm_task_set_name(dmt, name))
goto out;
if (dmd->uuid && !dm_task_set_uuid(dmt, dev_uuid))
if (uuid && !dm_task_set_uuid(dmt, dev_uuid))
goto out;
if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
@@ -523,11 +561,41 @@ out_no_removal:
return r;
}
static int dm_status_dmi(const char *name, struct dm_info *dmi)
int dm_create_device(const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
int reload)
{
char *table_params = NULL;
table_params = get_dm_crypt_params(dmd);
if (!table_params)
return -EINVAL;
return _dm_create_device(name, type, dmd->device, dmd->flags,
dmd->uuid, dmd->size, table_params, reload);
}
int dm_create_verity(const char *name,
struct crypt_params_verity *params,
struct crypt_dm_active_verity *dmd)
{
char *table_params = NULL;
table_params = get_dm_verity_params(params, dmd);
if (!table_params)
return -EINVAL;
return _dm_create_device(name, CRYPT_VERITY, dmd->data_device, dmd->flags,
NULL, dmd->size, table_params, 0);
}
static int dm_status_dmi(const char *name, struct dm_info *dmi,
const char *target, char **status_line)
{
struct dm_task *dmt;
uint64_t start, length;
char *target_type, *params;
char *target_type, *params = NULL;
void *next = NULL;
int r = -EINVAL;
@@ -550,12 +618,15 @@ static int dm_status_dmi(const char *name, struct dm_info *dmi)
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 ||
if (!target_type || strcmp(target_type, target) != 0 ||
start != 0 || next)
r = -EINVAL;
else
r = 0;
out:
if (!r && status_line && !(*status_line = strdup(params)))
r = -ENOMEM;
if (dmt)
dm_task_destroy(dmt);
@@ -567,7 +638,7 @@ int dm_status_device(const char *name)
int r;
struct dm_info dmi;
r = dm_status_dmi(name, &dmi);
r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
if (r < 0)
return r;
@@ -579,13 +650,32 @@ int dm_status_suspended(const char *name)
int r;
struct dm_info dmi;
r = dm_status_dmi(name, &dmi);
r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
if (r < 0)
return r;
return dmi.suspended ? 1 : 0;
}
int dm_status_verity_ok(const char *name)
{
int r;
struct dm_info dmi;
char *status_line = NULL;
r = dm_status_dmi(name, &dmi, DM_VERITY_TARGET, &status_line);
if (r < 0 || !status_line) {
free(status_line);
return r;
}
log_dbg("Verity volume %s status is %s.", name, status_line ?: "");
r = status_line[0] == 'V' ? 1 : 0;
free(status_line);
return r;
}
int dm_query_device(const char *name, uint32_t get_flags,
struct crypt_dm_active_device *dmd)
{
@@ -731,6 +821,14 @@ out:
return r;
}
int dm_query_verity(const char *name,
struct crypt_dm_active_verity *dmd)
{
int r = -EINVAL;
return r;
}
static int _dm_message(const char *name, const char *msg)
{
int r = 0;

View File

@@ -29,6 +29,7 @@
#include "libcryptsetup.h"
#include "luks.h"
#include "loopaes.h"
#include "verity.h"
#include "internal.h"
struct crypt_device {
@@ -64,6 +65,12 @@ struct crypt_device {
char *loopaes_uuid;
unsigned int loopaes_key_size;
/* used in CRYPT_VERITY */
struct crypt_params_verity verity_hdr;
uint32_t verity_flags;
char *verity_root_hash;
uint64_t verity_root_hash_size;
/* callbacks definitions */
void (*log)(int level, const char *msg, void *usrptr);
void *log_usrptr;
@@ -222,6 +229,11 @@ static int isLOOPAES(const char *type)
return (type && !strcmp(CRYPT_LOOPAES, type));
}
static int isVERITY(const char *type)
{
return (type && !strcmp(CRYPT_VERITY, type));
}
/* keyslot helpers */
static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
{
@@ -583,7 +595,7 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
log_dbg("Setting ciphertext data device to %s.", device ?: "(none)");
if (!isLUKS(cd->type)) {
if (!isLUKS(cd->type) && !isVERITY(cd->type)) {
log_err(cd, _("This operation is not supported for this device type.\n"));
return -EINVAL;
}
@@ -630,6 +642,37 @@ static int _crypt_load_luks1(struct crypt_device *cd, int require_header, int re
return r;
}
static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verity *params)
{
int r;
size_t sb_offset = 0;
r = init_crypto(cd);
if (r < 0)
return r;
if (params)
sb_offset = params->hash_area_offset;
r = VERITY_read_sb(cd, mdata_device(cd), sb_offset, &cd->verity_hdr);
if (r < 0)
return r;
if (params)
cd->verity_flags = params->flags;
if (params && params->data_device &&
(r = crypt_set_data_device(cd, params->data_device)) < 0)
return r;
cd->verity_root_hash_size = crypt_hash_size(cd->verity_hdr.hash_name);
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY)))
return -ENOMEM;
return r;
}
int crypt_init_by_name_and_header(struct crypt_device **cd,
const char *name,
const char *header_device)
@@ -909,6 +952,85 @@ static int _crypt_format_loopaes(struct crypt_device *cd,
return 0;
}
static int _crypt_format_verity(struct crypt_device *cd,
struct crypt_params_verity *params)
{
int r = 0;
uint64_t data_device_size;
if (!mdata_device(cd)) {
log_err(cd, _("Can't format VERITY without device.\n"));
return -EINVAL;
}
if (!params || !params->data_device)
return -EINVAL;
if (params->version > 1)
return -EINVAL;
/* set dat device */
cd->type = CRYPT_VERITY;
r = crypt_set_data_device(cd, params->data_device);
cd->type = NULL;
if (r)
return r;
if (!params->data_size) {
r = device_size(params->data_device, &data_device_size);
if (r < 0)
return r;
cd->verity_hdr.data_size = data_device_size / params->data_block_size;
} else
cd->verity_hdr.data_size = params->data_size;
cd->verity_root_hash_size = crypt_hash_size(params->hash_name);
if (!cd->verity_root_hash_size)
return -EINVAL;
cd->verity_flags = params->flags;
cd->verity_root_hash = malloc(cd->verity_root_hash_size);
if (!cd->verity_root_hash)
return -ENOMEM;
cd->verity_hdr.hash_name = strdup(params->hash_name);
cd->verity_hdr.data_device = NULL;
cd->verity_hdr.data_block_size = params->data_block_size;
cd->verity_hdr.hash_block_size = params->hash_block_size;
cd->verity_hdr.hash_area_offset = params->hash_area_offset;
cd->verity_hdr.version = params->version;
cd->verity_hdr.flags = params->flags;
cd->verity_hdr.salt_size = params->salt_size;
cd->verity_hdr.salt = malloc(params->salt_size);
if (params->salt)
memcpy(CONST_CAST(char*)cd->verity_hdr.salt, params->salt,
params->salt_size);
else
r = crypt_random_get(cd, CONST_CAST(char*)cd->verity_hdr.salt,
params->salt_size, CRYPT_RND_SALT);
if (r)
goto out;
log_dbg("Creating verity hash on device %s.", mdata_device(cd));
r = VERITY_create(cd, &cd->verity_hdr, cd->device, mdata_device(cd),
cd->verity_root_hash, cd->verity_root_hash_size);
if (r)
goto out;
r = VERITY_write_sb(cd, mdata_device(cd),
cd->verity_hdr.hash_area_offset,
&cd->verity_hdr);
out:
if (r) {
free(cd->verity_root_hash);
free(CONST_CAST(char*)cd->verity_hdr.hash_name);
free(CONST_CAST(char*)cd->verity_hdr.salt);
}
return r;
}
int crypt_format(struct crypt_device *cd,
const char *type,
const char *cipher,
@@ -942,6 +1064,8 @@ int crypt_format(struct crypt_device *cd,
uuid, volume_key, volume_key_size, params);
else if (isLOOPAES(type))
r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, params);
else if (isVERITY(type))
r = _crypt_format_verity(cd, params);
else {
/* FIXME: allow plugins here? */
log_err(cd, _("Unknown crypt device type %s requested.\n"), type);
@@ -961,7 +1085,7 @@ int crypt_format(struct crypt_device *cd,
int crypt_load(struct crypt_device *cd,
const char *requested_type,
void *params __attribute__((unused)))
void *params)
{
int r;
@@ -971,15 +1095,22 @@ int crypt_load(struct crypt_device *cd,
if (!mdata_device(cd))
return -EINVAL;
if (requested_type && !isLUKS(requested_type))
if (!requested_type || isLUKS(requested_type)) {
if (cd->type && !isLUKS(cd->type)) {
log_dbg("Context is already initialised to type %s", cd->type);
return -EINVAL;
}
r = _crypt_load_luks1(cd, 1, 0);
} else if (isVERITY(requested_type)) {
if (cd->type && !isVERITY(cd->type)) {
log_dbg("Context is already initialised to type %s", cd->type);
return -EINVAL;
}
r = _crypt_load_verity(cd, params);
} else
return -EINVAL;
if (cd->type && !isLUKS(cd->type)) {
log_dbg("Context is already initialised to type %s", cd->type);
return -EINVAL;
}
r = _crypt_load_luks1(cd, 1, 0);
if (r < 0)
return r;
@@ -1159,6 +1290,11 @@ void crypt_free(struct crypt_device *cd)
free(cd->loopaes_cipher);
free(cd->loopaes_uuid);
/* used in verity device only */
free(CONST_CAST(void*)cd->verity_hdr.hash_name);
free(CONST_CAST(void*)cd->verity_hdr.salt);
free(cd->verity_root_hash);
free(cd);
}
}
@@ -1783,6 +1919,27 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
if (!r && name)
r = LUKS1_activate(cd, name, vk, flags);
} else if (isVERITY(cd->type)) {
/* volume_key == root hash */
if (!volume_key || !volume_key_size) {
log_err(cd, _("Incorrect root hash specified for verity device.\n"));
return -EINVAL;
}
r = VERITY_activate(cd, name, mdata_device(cd),
volume_key, volume_key_size,
&cd->verity_hdr, cd->verity_flags);
if (r == -EPERM) {
free(cd->verity_root_hash);
cd->verity_root_hash = NULL;
} if (!r) {
cd->verity_root_hash_size = volume_key_size;
if (!cd->verity_root_hash)
cd->verity_root_hash = malloc(volume_key_size);
if (cd->verity_root_hash)
memcpy(cd->verity_root_hash, volume_key, volume_key_size);
}
} else
log_err(cd, _("Device type is not properly initialised.\n"));
@@ -1968,20 +2125,16 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
return CRYPT_INACTIVE;
}
static void hexprintICB(struct crypt_device *cd, char *d, int n)
static void hexprint(struct crypt_device *cd, const char *d, int n, const char *sep)
{
int i;
for(i = 0; i < n; i++)
log_std(cd, "%02hhx ", (char)d[i]);
log_std(cd, "%02hhx%s", (const char)d[i], sep);
}
int crypt_dump(struct crypt_device *cd)
static int _luks_dump(struct crypt_device *cd)
{
int i;
if (!isLUKS(cd->type)) { //FIXME
log_err(cd, _("This operation is supported only for LUKS device.\n"));
return -EINVAL;
}
log_std(cd, "LUKS header information for %s\n\n", mdata_device(cd));
log_std(cd, "Version: \t%d\n", cd->hdr.version);
@@ -1991,12 +2144,12 @@ int crypt_dump(struct crypt_device *cd)
log_std(cd, "Payload offset:\t%d\n", cd->hdr.payloadOffset);
log_std(cd, "MK bits: \t%d\n", cd->hdr.keyBytes * 8);
log_std(cd, "MK digest: \t");
hexprintICB(cd, cd->hdr.mkDigest, LUKS_DIGESTSIZE);
hexprint(cd, cd->hdr.mkDigest, LUKS_DIGESTSIZE, " ");
log_std(cd, "\n");
log_std(cd, "MK salt: \t");
hexprintICB(cd, cd->hdr.mkDigestSalt, LUKS_SALTSIZE/2);
hexprint(cd, cd->hdr.mkDigestSalt, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n \t");
hexprintICB(cd, cd->hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
hexprint(cd, cd->hdr.mkDigestSalt+LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n");
log_std(cd, "MK iterations: \t%d\n", cd->hdr.mkDigestIterations);
log_std(cd, "UUID: \t%s\n\n", cd->hdr.uuid);
@@ -2006,11 +2159,11 @@ int crypt_dump(struct crypt_device *cd)
log_std(cd, "\tIterations: \t%d\n",
cd->hdr.keyblock[i].passwordIterations);
log_std(cd, "\tSalt: \t");
hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2);
hexprint(cd, cd->hdr.keyblock[i].passwordSalt,
LUKS_SALTSIZE/2, " ");
log_std(cd, "\n\t \t");
hexprintICB(cd, cd->hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2);
hexprint(cd, cd->hdr.keyblock[i].passwordSalt +
LUKS_SALTSIZE/2, LUKS_SALTSIZE/2, " ");
log_std(cd, "\n");
log_std(cd, "\tKey material offset:\t%d\n",
@@ -2021,10 +2174,42 @@ int crypt_dump(struct crypt_device *cd)
else
log_std(cd, "Key Slot %d: DISABLED\n", i);
}
return 0;
}
static int _verity_dump(struct crypt_device *cd)
{
log_std(cd, "VERITY header information for %s\n", mdata_device(cd));
log_std(cd, "Version: \t%u\n", cd->verity_hdr.version);
log_std(cd, "Data blocks: \t%" PRIu64 "\n", cd->verity_hdr.data_size);
log_std(cd, "Data block size: \t%u\n", cd->verity_hdr.data_block_size);
log_std(cd, "Hash block size: \t%u\n", cd->verity_hdr.hash_block_size);
log_std(cd, "Hash algorithm: \t%s\n", cd->verity_hdr.hash_name);
log_std(cd, "Salt: \t");
if (cd->verity_hdr.salt_size)
hexprint(cd, cd->verity_hdr.salt, cd->verity_hdr.salt_size, "");
else
log_std(cd, "-");
log_std(cd, "\n");
if (cd->verity_root_hash) {
log_std(cd, "Root hash: \t");
hexprint(cd, cd->verity_root_hash, cd->verity_root_hash_size, "");
log_std(cd, "\n");
}
return 0;
}
int crypt_dump(struct crypt_device *cd)
{
if (isLUKS(cd->type))
return _luks_dump(cd);
else if (isVERITY(cd->type))
return _verity_dump(cd);
log_err(cd, _("Dump operation is not supported for this device type.\n"));
return -EINVAL;
}
const char *crypt_get_cipher(struct crypt_device *cd)
{
if (isPLAIN(cd->type))
@@ -2072,7 +2257,6 @@ const char *crypt_get_device_name(struct crypt_device *cd)
return cd->device;
}
int crypt_get_volume_key_size(struct crypt_device *cd)
{
if (isPLAIN(cd->type))
@@ -2084,6 +2268,9 @@ int crypt_get_volume_key_size(struct crypt_device *cd)
if (isLOOPAES(cd->type))
return cd->loopaes_key_size;
if (isVERITY(cd->type))
return cd->verity_root_hash_size;
return 0;
}

View File

@@ -27,6 +27,7 @@
struct crypt_device;
struct volume_key;
struct crypt_params_verity;
/* Device mapper backend - kernel support flags */
#define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */
@@ -57,18 +58,36 @@ struct crypt_dm_active_device {
uint32_t flags; /* activation flags */
};
struct crypt_dm_active_verity {
const char *data_device;
const char *hash_device;
const char *root_hash;
size_t root_hash_size;
uint64_t hash_offset; /* hash offset (not header) */
uint64_t size; /* active device size */
uint32_t flags; /* activation flags */
};
const char *dm_get_dir(void);
int dm_init(struct crypt_device *context, int check_kernel);
void dm_exit(void);
int dm_remove_device(const char *name, int force, uint64_t size);
int dm_status_device(const char *name);
int dm_status_suspended(const char *name);
int dm_status_verity_ok(const char *name);
int dm_query_device(const char *name, uint32_t get_flags,
struct crypt_dm_active_device *dmd);
int dm_query_verity(const char *name,
struct crypt_dm_active_verity *dmd);
int dm_create_device(const char *name,
const char *type,
struct crypt_dm_active_device *dmd,
int reload);
int dm_create_verity(const char *name,
struct crypt_params_verity *params,
struct crypt_dm_active_verity *dmd);
int dm_suspend_and_wipe_key(const char *name);
int dm_resume_and_reinstate_key(const char *name,
size_t key_size,

16
lib/verity/Makefile.am Normal file
View File

@@ -0,0 +1,16 @@
moduledir = $(libdir)/cryptsetup
noinst_LTLIBRARIES = libverity.la
libverity_la_CFLAGS = -Wall @CRYPTO_CFLAGS@
libverity_la_SOURCES = \
verity_hash.c \
verity.c \
verity.h
INCLUDES = -D_GNU_SOURCE \
-D_LARGEFILE64_SOURCE \
-D_FILE_OFFSET_BITS=64 \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/lib/crypto_backend

203
lib/verity/verity.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include "libcryptsetup.h"
#include "verity.h"
#include "internal.h"
/* Read verity superblock from disk */
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
size_t sb_offset,
struct crypt_params_verity *params)
{
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int devfd = 0;
long long sb_data_blocks;
log_dbg("Reading VERITY header of size %d on device %s, offset %u.",
sizeof(struct verity_sb), device, (unsigned)sb_offset);
devfd = open(device ,O_RDONLY | O_DIRECT);
if(devfd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device);
return -EINVAL;
}
if(lseek(devfd, sb_offset, SEEK_SET) < 0 ||
read_blockwise(devfd, &sb, hdr_size) < hdr_size) {
close(devfd);
return -EIO;
}
close(devfd);
if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) {
log_err(cd, _("Device %s is not a valid VERITY device.\n"), device);
return -EINVAL;
}
if (sb.version > 1) {
log_err(cd, _("Unsupported VERITY version %d.\n"), sb.version);
return -EINVAL;
}
if (sb.data_block_bits < 9 || sb.data_block_bits >= 31 ||
sb.hash_block_bits < 9 || sb.hash_block_bits >= 31 ||
!memchr(sb.algorithm, 0, sizeof(sb.algorithm)) ||
ntohs(sb.salt_size) > VERITY_MAX_SALT_SIZE) {
log_err(cd, _("VERITY header corrupted.\n"));
return -EINVAL;
}
sb_data_blocks = ((unsigned long long)ntohl(sb.data_blocks_hi) << 31 << 1) |
ntohl(sb.data_blocks_lo);
if (sb_data_blocks < 0 ||
(off_t)sb_data_blocks < 0 ||
(off_t)sb_data_blocks != sb_data_blocks) {
log_err(cd, _("VERITY header data block size mismatch.\n"));
return -EINVAL;
}
// FIXME alloc error
params->hash_name = strdup((const char*)sb.algorithm);
params->data_block_size = 1 << sb.data_block_bits;
params->hash_block_size = 1 << sb.hash_block_bits;
params->data_size = sb_data_blocks;
params->salt_size = ntohs(sb.salt_size);
params->salt = malloc(params->salt_size);
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
params->hash_area_offset = sb_offset;
params->version = sb.version;
return 0;
}
/* Write verity superblock to disk */
int VERITY_write_sb(struct crypt_device *cd,
const char *device,
size_t sb_offset,
struct crypt_params_verity *params)
{
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
int r, devfd = 0;
log_dbg("Updating VERITY header of size %d on device %s, offset %u.",
sizeof(struct verity_sb), device, (unsigned)sb_offset);
devfd = open(device, O_RDWR | O_DIRECT);
if(devfd == -1) {
log_err(cd, _("Cannot open device %s.\n"), device);
return -EINVAL;
}
memcpy(&sb.signature, VERITY_SIGNATURE, sizeof(sb.signature));
sb.version = params->version;
sb.data_block_bits = ffs(params->data_block_size) - 1;
sb.hash_block_bits = ffs(params->hash_block_size) - 1;
sb.salt_size = htons(params->salt_size);
sb.data_blocks_hi = htonl(params->data_size >> 31 >> 1);
sb.data_blocks_lo = htonl(params->data_size & 0xFFFFFFFF);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
r = write_lseek_blockwise(devfd, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
log_err(cd, _("Error during update of verity header on device %s.\n"), device);
close(devfd);
return r;
}
/* Calculate hash offset in hash blocks */
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params)
{
uint64_t hash_offset = params->hash_area_offset;
if (params->flags & CRYPT_VERITY_NO_HEADER)
return hash_offset / params->hash_block_size;
hash_offset += sizeof(struct verity_sb);
hash_offset += params->hash_block_size - 1;
return hash_offset / params->hash_block_size;
}
/* Activate verity device in kernel device-mapper */
int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *hash_device,
const char *root_hash,
size_t root_hash_size,
struct crypt_params_verity *verity_hdr,
uint32_t flags)
{
struct crypt_dm_active_verity dmd;
uint64_t offset = 0;
int r;
log_dbg("Trying to activate VERITY device %s using hash %s.",
name ?: "[none]", verity_hdr->hash_name);
if (flags & CRYPT_VERITY_CHECK_HASH) {
r = VERITY_verify(cd, verity_hdr,
crypt_get_device_name(cd), hash_device,
root_hash, root_hash_size);
if (r < 0)
return r;
}
if (!name)
return 0;
dmd.data_device = crypt_get_device_name(cd);
dmd.hash_device = hash_device;
dmd.root_hash = root_hash;
dmd.root_hash_size = root_hash_size;
dmd.hash_offset = VERITY_hash_offset_block(verity_hdr),
dmd.flags = CRYPT_ACTIVATE_READONLY;
dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
&dmd.size, &offset, &dmd.flags);
if (r)
return r;
r = dm_create_verity(name, verity_hdr, &dmd);
if (r < 0)
return r;
r = dm_status_verity_ok(name);
if (r < 0)
return r;
if (!r)
log_err(cd, _("Verity device detected corruption after activation.\n"));
return 0;
}

83
lib/verity/verity.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _VERITY_H
#define _VERITY_H
#include <unistd.h>
#include "config.h"
#define VERITY_SIGNATURE "verity\0\0"
#define VERITY_MAX_LEVELS 63
#define VERITY_MAX_SALT_SIZE 384
struct crypt_device;
struct crypt_params_verity;
/* FIXME: not yet final on-disk format! Add UUID etc */
struct verity_sb {
uint8_t signature[8];
uint8_t version;
uint8_t data_block_bits;
uint8_t hash_block_bits;
uint8_t pad1[1];
uint16_t salt_size;
uint8_t pad2[2];
uint32_t data_blocks_hi;
uint32_t data_blocks_lo;
uint8_t algorithm[16];
uint8_t salt[VERITY_MAX_SALT_SIZE];
uint8_t pad3[88];
};
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
size_t sb_offset,
struct crypt_params_verity *params);
int VERITY_write_sb(struct crypt_device *cd,
const char *device,
size_t sb_offset,
struct crypt_params_verity *params);
int VERITY_activate(struct crypt_device *cd,
const char *name,
const char *hash_device,
const char *root_hash,
size_t root_hash_size,
struct crypt_params_verity *verity_hdr,
uint32_t flags);
int VERITY_verify(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *data_device,
const char *hash_device,
const char *root_hash,
size_t root_hash_size);
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *data_device,
const char *hash_device,
char *root_hash,
size_t root_hash_size);
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
#endif

376
lib/verity/verity_hash.c Normal file
View File

@@ -0,0 +1,376 @@
/*
* dm-verity volume handling
*
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "verity.h"
#include "internal.h"
static unsigned get_bits_up(unsigned u)
{
unsigned i = 0;
while ((1 << i) < u)
i++;
return i;
}
static unsigned get_bits_down(unsigned u)
{
unsigned i = 0;
while ((u >> i) > 1)
i++;
return i;
}
static int verify_zero(struct crypt_device *cd, FILE *wr, unsigned bytes)
{
unsigned i;
char block[bytes];
if (fread(block, bytes, 1, wr) != 1)
return -EIO;
for (i = 0; i < bytes; i++)
if (block[i]) {
log_err(cd, "spare area is not zeroed at position %lld\n",
(long long)ftello(wr) - bytes);
return -EPERM;
}
return 0;
}
static int verify_hash_block(const char *hash_name, int version,
char *hash, size_t hash_size,
const char *data, size_t data_size,
const char *salt, size_t salt_size)
{
struct crypt_hash *ctx = NULL;
int r;
if (crypt_hash_init(&ctx, hash_name))
return -EINVAL;
if (version == 1 && (r = crypt_hash_write(ctx, salt, salt_size)))
goto out;
if ((r = crypt_hash_write(ctx, data, data_size)))
goto out;
if (version == 0 && (r = crypt_hash_write(ctx, salt, salt_size)))
goto out;
r = crypt_hash_final(ctx, hash, hash_size);
out:
crypt_hash_destroy(ctx);
return r;
}
static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
off_t data_block, int data_block_size,
off_t hash_block, int hash_block_size,
off_t blocks, int version,
const char *hash_name, int verify,
char *calculated_digest, unsigned digest_size,
const char *salt, unsigned salt_size)
{
char left_block[hash_block_size];
char data_buffer[data_block_size];
char read_digest[digest_size];
off_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
off_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
unsigned i, left_bytes;
off_t digest_size_full = 1 << get_bits_up(digest_size);
int r;
unsigned long long pos_rd = (unsigned long long)data_block * data_block_size;
unsigned long long pos_wr = (unsigned long long)hash_block * hash_block_size;
if (fseeko(rd, pos_rd, SEEK_SET))
return -EIO;
if (wr && fseeko(wr, pos_wr, SEEK_SET))
return -EIO;
memset(left_block, 0, hash_block_size);
while (blocks_to_write--) {
left_bytes = hash_block_size;
for (i = 0; i < hash_per_block; i++) {
if (!blocks)
break;
blocks--;
if (fread(data_buffer, data_block_size, 1, rd) != 1)
return -EIO;
if (verify_hash_block(hash_name, version,
calculated_digest, digest_size,
data_buffer, data_block_size,
salt, salt_size))
return -EINVAL;
if (!wr)
break;
if (verify) {
if (fread(read_digest, digest_size, 1, wr) != 1)
return -EIO;
if (memcmp(read_digest, calculated_digest, digest_size)) {
log_err(cd, "verification failed at position %lld\n",
(long long)ftello(rd) - data_block_size);
return -EPERM;
}
} else {
if (fwrite(calculated_digest, digest_size, 1, wr) != 1)
return -EIO;
}
if (version == 0) {
left_bytes -= digest_size;
} else {
if (digest_size_full - digest_size) {
if (verify) {
r = verify_zero(cd, wr, digest_size_full - digest_size);
if (r)
return r;
} else if (fwrite(left_block, digest_size_full - digest_size, 1, wr) != 1)
return -EIO;
}
left_bytes -= digest_size_full;
}
}
if (wr && left_bytes) {
if (verify) {
r = verify_zero(cd , wr, left_bytes);
if (r)
return r;
} else if (fwrite(left_block, left_bytes, 1, wr) != 1)
return -EIO;
}
}
return 0;
}
static int VERITY_create_or_verify_hash(struct crypt_device *cd,
int verify,
int version,
const char *hash_name,
const char *hash_device,
const char *data_device,
int hash_block_size,
int data_block_size,
off_t data_blocks,
long long hash_position,
char *root_hash,
unsigned digest_size,
const char *salt,
unsigned salt_size)
{
static FILE *data_file = NULL;
static FILE *hash_file = NULL, *hash_file_2;
int i, r;
char calculated_digest[digest_size];
off_t hash_level_block[VERITY_MAX_LEVELS];
off_t hash_level_size[VERITY_MAX_LEVELS];
off_t data_file_blocks;
uint64_t data_device_size;
unsigned long long hash_per_block, hash_per_block_bits;
unsigned levels;
log_dbg("Userspace hash %s %s, data device %s, data blocks %u, hash device %s, offset %u.",
verify ? "verification" : "creation", hash_name, data_device,
(unsigned)data_blocks, hash_device, (unsigned)hash_position);
if (!data_blocks) {
r = device_size(data_device, &data_device_size);
if (r < 0)
return r;
data_file_blocks = data_device_size / data_block_size;
} else
data_file_blocks = data_blocks;
hash_per_block_bits = get_bits_down(hash_block_size / digest_size);
hash_per_block = 1 << hash_per_block_bits;
if (!hash_per_block_bits) {
log_err(cd, "at least two hashes must fit in a hash file block\n");
return -EINVAL;
}
levels = 0;
if (data_file_blocks) {
while (hash_per_block_bits * levels < 64 &&
(unsigned long long)(data_file_blocks - 1) >>
(hash_per_block_bits * levels))
levels++;
}
if (levels > VERITY_MAX_LEVELS) {
log_err(cd, "too many tree levels\n");
return -EINVAL;
}
for (i = levels - 1; i >= 0; i--) {
off_t s;
hash_level_block[i] = hash_position;
// verity position of block data_file_blocks at level i
s = data_file_blocks >> (i * hash_per_block_bits);
s = (s + hash_per_block - 1) / hash_per_block;
hash_level_size[i] = s;
if (hash_position + s < hash_position ||
(off_t)(hash_position + s) < 0 ||
(off_t)(hash_position + s) != hash_position + s) {
log_err(cd, "hash device offset overflow\n");
return -EINVAL;
}
hash_position += s;
}
data_file = fopen(data_device, "r");
if (!data_file) {
log_err(cd, "Cannot open %s.\n", data_device);
r = -EIO;
goto out;
}
hash_file = fopen(hash_device, verify ? "r" : "r+");
if (!hash_file) {
log_err(cd, "Cannot open %s.\n", hash_device);
r = -EIO;
goto out;
}
memset(calculated_digest, 0, digest_size);
for (i = 0; i < levels; i++) {
if (!i) {
r = create_or_verify(cd, data_file, hash_file,
0, data_block_size,
hash_level_block[i], hash_block_size,
data_file_blocks, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
if (r)
goto out;
} else {
hash_file_2 = fopen(hash_device, "r");
if (!hash_file_2) {
r = -EIO;
goto out;
}
r = create_or_verify(cd, hash_file_2, hash_file,
hash_level_block[i - 1], hash_block_size,
hash_level_block[i], hash_block_size,
hash_level_size[i - 1], version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
fclose(hash_file_2);
if (r)
goto out;
}
}
if (levels)
r = create_or_verify(cd, hash_file, NULL,
hash_level_block[levels - 1], hash_block_size,
0, 0,
1, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
else
r = create_or_verify(cd, data_file, NULL,
0, data_block_size,
0, 0,
data_file_blocks, version, hash_name, verify,
calculated_digest, digest_size, salt, salt_size);
if (r) {
log_err(cd, "Hash of data area verification failed.\n");
goto out;
} else
log_dbg("Hash of data area successfully verified.");
/* root hash verification */
if (verify) {
r = memcmp(root_hash, calculated_digest, digest_size) ? -EPERM : 0;
if (r)
log_err(cd, "Root hash verification failed.\n");
else
log_dbg("Root hash successfully verified.");
} else {
fsync(fileno(hash_file));
memcpy(root_hash, calculated_digest, digest_size);
}
out:
if (data_file)
fclose(data_file);
if (hash_file)
fclose(hash_file);
return r;
}
/* Verify verity device using userspace crypto backend */
int VERITY_verify(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *data_device,
const char *hash_device,
const char *root_hash,
size_t root_hash_size)
{
int r = VERITY_create_or_verify_hash(cd, 1,
verity_hdr->version,
verity_hdr->hash_name,
hash_device,
data_device,
verity_hdr->hash_block_size,
verity_hdr->data_block_size,
verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr),
CONST_CAST(char*)root_hash,
root_hash_size,
verity_hdr->salt,
verity_hdr->salt_size);
if (r == -EPERM)
log_err(cd, "Userspace hash verification failed.\n");
return r;
}
int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *data_device,
const char *hash_device,
char *root_hash,
size_t root_hash_size)
{
if (verity_hdr->salt_size > VERITY_MAX_SALT_SIZE)
return -EINVAL;
return VERITY_create_or_verify_hash(cd, 0,
verity_hdr->version,
verity_hdr->hash_name,
hash_device,
data_device,
verity_hdr->hash_block_size,
verity_hdr->data_block_size,
verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr),
root_hash,
root_hash_size,
verity_hdr->salt,
verity_hdr->salt_size);
}

View File

@@ -39,14 +39,12 @@ endif
# veritysetup
if VERITYSETUP
INCLUDES += -I$(top_srcdir)/lib/crypto_backend
veritysetup_SOURCES = \
veritysetup.c
veritysetup_LDADD = \
$(top_builddir)/lib/crypto_backend/libcrypto_backend.la \
@CRYPTO_LIBS@ \
$(top_builddir)/lib/libcryptsetup.la \
@POPT_LIBS@
veritysetup_CFLAGS = $(cryptsetup_CFLAGS)
@@ -59,6 +57,8 @@ veritysetup_static_SOURCES = $(veritysetup_SOURCES)
veritysetup_static_CFLAGS = $(veritysetup_CFLAGS)
veritysetup_static_LDFLAGS = -all-static
veritysetup_static_LDADD = $(veritysetup_LDADD) \
@CRYPTO_STATIC_LIBS@
@CRYPTO_STATIC_LIBS@ \
@DEVMAPPER_STATIC_LIBS@ \
@UUID_LIBS@
endif
endif

View File

@@ -32,7 +32,6 @@
#include <fcntl.h>
#include <assert.h>
#include <limits.h>
#include <libcryptsetup.h>
#include <popt.h>
#include "cryptsetup.h"

View File

@@ -29,6 +29,8 @@
#include "lib/utils_loop.h"
#include "lib/utils_fips.h"
#include "libcryptsetup.h"
#define DEFAULT_CIPHER(type) (DEFAULT_##type##_CIPHER "-" DEFAULT_##type##_MODE)
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)

File diff suppressed because it is too large Load Diff

View File

@@ -21,8 +21,9 @@ function remove_mapping()
function fail()
{
[ -n "$1" ] && echo "$1"
remove_mapping
echo "FAILED"
[ -f $DEV_OUT ] && cat $DEV_OUT
remove_mapping
exit 2
}
@@ -52,6 +53,7 @@ function wipe()
{
dd if=/dev/zero of=$LOOPDEV1 bs=256k >/dev/null 2>&1
dd if=/dev/zero of=$LOOPDEV2 bs=256k >/dev/null 2>&1
rm -f $DEV_OUT >/dev/null 2>&1
}
function check_exists()
@@ -61,17 +63,17 @@ function check_exists()
function compare_out() # $1 what, $2 expected
{
OPT=$(grep "$1" $DEV_OUT | sed -e s/.*\:\ //)
OPT=$(grep -v "^#" $DEV_OUT | grep -i "$1" | sed -e s/.*\:\ //)
[ -z "$OPT" ] && fail
[ $OPT != $2 ] && fail "$1 differs ($OPT)"
}
function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, [$5 offset]
function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, $5 hash, [$6 offset]
{
if [ -z "$LOOPDEV2" ] ; then
BLOCKS=$(($5 * 512 / $1))
BLOCKS=$(($6 * 512 / $1))
DEV_PARAMS="$LOOPDEV1 $LOOPDEV1 \
--hash-start $5 \
--hash-start $6 \
--data-blocks=$BLOCKS"
else
DEV_PARAMS="$LOOPDEV1 $LOOPDEV2"
@@ -79,20 +81,20 @@ function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, [$5 offset]
for fail in data hash; do
wipe
echo -n "V$4 block size $1: "
echo -n "V$4 $5 block size $1: "
$VERITYSETUP -c $DEV_PARAMS --format=$4 \
--data-block-size=$1 --hash-block-size=$1 \
--algorithm=sha256 --salt=$3 \
--algorithm=$5 --salt=$3 \
>$DEV_OUT || fail
echo -n "[root hash]"
compare_out "root hash" $2
compare_out "salt" "$3"
compare_out "alt" "$3"
$VERITYSETUP -v $DEV_PARAMS $2 >/dev/null 2>&1 || fail
$VERITYSETUP -v $DEV_PARAMS $2 >>$DEV_OUT 2>&1 || fail
echo -n "[verify]"
$VERITYSETUP -a $DEV_NAME $DEV_PARAMS $2 >/dev/null 2>&1 || fail
$VERITYSETUP -a $DEV_NAME $DEV_PARAMS $2 >>$DEV_OUT 2>&1 || fail
check_exists
echo -n "[activate]"
@@ -117,9 +119,9 @@ function check_root_hash() # $1 size, $2 hash, $3 salt, $4 version, [$5 offset]
;;
esac
$VERITYSETUP -v $DEV_PARAMS $2 >/dev/null 2>&1 && \
$VERITYSETUP -v $DEV_PARAMS $2 >>$DEV_OUT 2>&1 && \
fail "userspace check for $TXT corruption"
$VERITYSETUP -a $DEV_NAME $DEV_PARAMS $2 >/dev/null 2>&1 || \
$VERITYSETUP -a $DEV_NAME $DEV_PARAMS $2 >>$DEV_OUT 2>&1 || \
fail "activation"
dd if=/dev/mapper/$DEV_NAME of=/dev/null bs=$1 2>/dev/null
dmsetup status $DEV_NAME | grep "verity V" >/dev/null && \
@@ -152,21 +154,25 @@ SALT=e48da609055204e89ae53b655ca2216dd983cf3cb829f34f63a297d106d53e2d
echo "Verity tests [separate devices]"
prepare 8192 1024
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1
check_root_hash 8192 7fbc02e9ffd56d0b3686c4fe8cbf20c72552df29317ea3b09a5e39a46a92d2f5 $SALT 1
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256
# version 0
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256
# sha1
check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1
check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1
echo "Verity tests [one device offset]"
prepare $((8192 + 1024))
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 16384
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 16384
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 16384
check_root_hash 8192 7fbc02e9ffd56d0b3686c4fe8cbf20c72552df29317ea3b09a5e39a46a92d2f5 $SALT 1 16384
check_root_hash 512 9de18652fe74edfb9b805aaed72ae2aa48f94333f1ba5c452ac33b1c39325174 $SALT 1 sha256 16384
check_root_hash 1024 54d92778750495d1f80832b486ebd007617d746271511bbf0e295e143da2b3df $SALT 1 sha256 16384
check_root_hash 4096 e522df0f97da4febb882ac40f30b37dc0b444bf6df418929463fa25280f09d5c $SALT 1 sha256 16384
# version 0
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 16384
check_root_hash 4096 cbbf4ebd004ef65e29b935bb635a39cf754d677f3fa10b0126da725bbdf10f7d $SALT 0 sha256 16384
# sha1
check_root_hash 1024 d0e9163ca8844aaa2e88fe5265a8c5d9ee494a99 $SALT 1 sha1 16384
check_root_hash 1024 73509e8e868be6b8ac939817a98a3d35121413b2 dadada 1 sha1 16384
remove_mapping
exit 0