mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-11 19:00:02 +01:00
Rewrite veritysetup to use libcryptsetup.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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, ¶ms);
|
||||
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;
|
||||
|
||||
237
lib/setup.c
237
lib/setup.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
16
lib/verity/Makefile.am
Normal 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
203
lib/verity/verity.c
Normal 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
83
lib/verity/verity.h
Normal 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
376
lib/verity/verity_hash.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <libcryptsetup.h>
|
||||
#include <popt.h>
|
||||
|
||||
#include "cryptsetup.h"
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user