struct crypt_params_verity verity_hdr;
char *verity_root_hash;
uint64_t verity_root_hash_size;
+ char *verity_uuid;
/* callbacks definitions */
void (*log)(int level, const char *msg, void *usrptr);
if (params)
sb_offset = params->hash_area_offset;
- r = VERITY_read_sb(cd, mdata_device(cd), sb_offset, &cd->verity_hdr);
+ r = VERITY_read_sb(cd, mdata_device(cd), sb_offset,
+ &cd->verity_uuid, &cd->verity_hdr);
if (r < 0)
return r;
goto out;
if (isVERITY(cd->type)) {
+ cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
cd->verity_hdr.flags = CRYPT_VERITY_NO_HEADER; //FIXME
- //cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
cd->verity_hdr.data_size = params.data_size;
cd->verity_root_hash_size = dmd.u.verity.root_hash_size;
cd->verity_root_hash = NULL;
}
static int _crypt_format_verity(struct crypt_device *cd,
+ const char *uuid,
struct crypt_params_verity *params)
{
int r = 0;
} 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;
r = crypt_random_get(cd, CONST_CAST(char*)cd->verity_hdr.salt,
params->salt_size, CRYPT_RND_SALT);
if (r)
- goto out;
+ return r;
if (params->flags & CRYPT_VERITY_CREATE_HASH) {
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;
+ return r;
}
- if (!(params->flags & CRYPT_VERITY_NO_HEADER))
+ if (!(params->flags & CRYPT_VERITY_NO_HEADER)) {
+ if (uuid)
+ cd->verity_uuid = strdup(uuid);
+ else {
+ r = VERITY_UUID_generate(cd, &cd->verity_uuid);
+ if (r)
+ return r;
+ }
+
r = VERITY_write_sb(cd, mdata_device(cd),
cd->verity_hdr.hash_area_offset,
+ cd->verity_uuid,
&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;
}
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);
+ r = _crypt_format_verity(cd, uuid, params);
else {
/* FIXME: allow plugins here? */
log_err(cd, _("Unknown crypt device type %s requested.\n"), type);
free(CONST_CAST(void*)cd->verity_hdr.hash_name);
free(CONST_CAST(void*)cd->verity_hdr.salt);
free(cd->verity_root_hash);
+ free(cd->verity_uuid);
free(cd);
}
static int _verity_dump(struct crypt_device *cd)
{
log_std(cd, "VERITY header information for %s\n", mdata_device(cd));
+ log_std(cd, "UUID: \t%s\n", cd->verity_uuid ?: "");
log_std(cd, "Hash type: \t%u\n", cd->verity_hdr.hash_type);
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);
if (isLOOPAES(cd->type))
return cd->loopaes_uuid;
+ if (isVERITY(cd->type))
+ return cd->verity_uuid;
+
return NULL;
}
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
+#include <uuid/uuid.h>
#include "libcryptsetup.h"
#include "verity.h"
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
uint64_t sb_offset,
+ char **uuid_string,
struct crypt_params_verity *params)
{
struct verity_sb sb = {};
}
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
+ if ((*uuid_string = malloc(40)))
+ uuid_unparse(sb.uuid, *uuid_string);
#endif
params->hash_area_offset = sb_offset;
return 0;
int VERITY_write_sb(struct crypt_device *cd,
const char *device,
uint64_t sb_offset,
+ const char *uuid_string,
struct crypt_params_verity *params)
{
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
+ uuid_t uuid;
int r, devfd = 0;
log_dbg("Updating VERITY header of size %u on device %s, offset %" PRIu64 ".",
sizeof(struct verity_sb), device, sb_offset);
+ if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) {
+ log_err(cd, _("Wrong VERITY UUID format provided.\n"), device);
+ return -EINVAL;
+ }
+
if (params->flags & CRYPT_VERITY_NO_HEADER) {
log_err(cd, _("Verity device doesn't use on-disk header.\n"), device);
return -EINVAL;
sb.data_blocks = cpu_to_le64(params->data_size);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
+ memcpy(sb.uuid, uuid, sizeof(sb.uuid));
#endif
r = write_lseek_blockwise(devfd, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
return hash_offset / params->hash_block_size;
}
+int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string)
+{
+ uuid_t uuid;
+
+ if (!(*uuid_string = malloc(40)))
+ return -ENOMEM;
+ uuid_generate(uuid);
+ uuid_unparse(uuid, *uuid_string);
+ return 0;
+}
+
/* Activate verity device in kernel device-mapper */
int VERITY_activate(struct crypt_device *cd,
const char *name,
dmd.u.verity.hash_offset = VERITY_hash_offset_block(verity_hdr),
dmd.flags = activation_flags;
dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
- dmd.uuid = NULL;
+ dmd.uuid = crypt_get_uuid(cd);
dmd.u.verity.vp = verity_hdr;
r = device_check_and_adjust(cd, dmd.data_device, DEV_EXCL,
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
uint64_t sb_offset,
+ char **uuid,
struct crypt_params_verity *params);
int VERITY_write_sb(struct crypt_device *cd,
const char *device,
uint64_t sb_offset,
+ const char *uuid_string,
struct crypt_params_verity *params);
int VERITY_activate(struct crypt_device *cd,
uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
+int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string);
+
#endif
\fB<options>\fR can be [\-\-hash, \-\-no-superblock, \-\-format,
\-\-data-block-size, \-\-hash-block-size, \-\-data-blocks, \-\-hash-start,
-\-\-salt]
+\-\-salt, \-\-uuid]
.PP
\fIcreate\fR <name> <data_device> <hash_device> <root_hash>
.IP
Run in debug mode with full diagnostic logs. Debug output
lines are always prefixed by '#'.
.TP
-.B "\-\-no-superblock
+.B "\-\-no-superblock"
Create or use dm-verity without permanent on-disk superblock.
.TP
-.B "\-\-format=number
+.B "\-\-format=number"
Specifies the hash version type.
Format type 0 is original Chrome OS verion. Format type 1 si default.
.TP
-.B "\-\-data-block-size=bytes
+.B "\-\-data-block-size=bytes"
Used block size for the data device.
(Note kernel supports only page-size as maximum here.)
.TP
-.B "\-\-hash-block-size=bytes
+.B "\-\-hash-block-size=bytes"
Used block size for the hash device.
(Note kernel supports only page-size as maximum here.)
.TP
-.B "\-\-data-blocks=blocks
+.B "\-\-data-blocks=blocks"
Size of data device used in verification.
If not specified, the whole device is used.
.TP
-.B "\-\-hash-start=512-bytes sectors
+.B "\-\-hash-start=512-bytes sectors"
Offset of hash area/superblock on hash_device.
.TP
-.B "\-\-salt=hex string
+.B "\-\-salt=hex string"
Salt used for format or verification.
Format is hexadecimal string.
.TP
+.B "\-\-uuid=UUID"
+Use the provided UUID for the format command
+instead of generating new one.
+
+The UUID must be provided in the standard UUID format,
+e.g. 12345678-1234-1234-1234-123456789abc.
+.TP
.B "\-\-version"
Show the program version.
.SH RETURN CODES
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-/* TODO:
- * - extend superblock (UUID)
- * - add api tests
- */
-
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
static uint64_t data_blocks = 0;
static const char *salt_string = NULL;
static uint64_t hash_start = 0;
+static const char *opt_uuid = NULL;
static int opt_verbose = 0;
static int opt_debug = 0;
if (r < 0)
goto out;
- r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, ¶ms);
+ r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, ¶ms);
if (!r)
crypt_dump(cd);
out:
{ "hash-start", 0, POPT_ARG_STRING, &popt_tmp, 2, N_("Starting block on the hash device"), N_("512-byte sectors") },
{ "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
{ "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
+ { "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL },
POPT_TABLEEND
};