--- /dev/null
+#ifndef BITOPS_H
+#define BITOPS_H
+
+#include <stdint.h>
+
+/*
+ * Bit map related macros. Usually provided by libc.
+ */
+#include <sys/param.h>
+
+#ifndef NBBY
+# define NBBY CHAR_BIT
+#endif
+
+#ifndef setbit
+# define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+# define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+# define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+# define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif
+
+/*
+ * Byte swab macros (based on linux/byteorder/swab.h)
+ */
+#define swab16(x) \
+ ((uint16_t)( \
+ (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
+ (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
+
+#define swab32(x) \
+ ((uint32_t)( \
+ (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#define swab64(x) \
+ ((uint64_t)( \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
+ (uint64_t)(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
+
+
+#ifdef WORDS_BIGENDIAN
+
+#define cpu_to_le16(x) swab16(x)
+#define cpu_to_le32(x) swab32(x)
+#define cpu_to_le64(x) swab64(x)
+#define cpu_to_be16(x) ((uint16_t)(x))
+#define cpu_to_be32(x) ((uint32_t)(x))
+#define cpu_to_be64(x) ((uint64_t)(x))
+
+#define le16_to_cpu(x) swab16(x)
+#define le32_to_cpu(x) swab32(x)
+#define le64_to_cpu(x) swab64(x)
+#define be16_to_cpu(x) ((uint16_t)(x))
+#define be32_to_cpu(x) ((uint32_t)(x))
+#define be64_to_cpu(x) ((uint64_t)(x))
+
+#else /* !WORDS_BIGENDIAN */
+
+#define cpu_to_le16(x) ((uint16_t)(x))
+#define cpu_to_le32(x) ((uint32_t)(x))
+#define cpu_to_le64(x) ((uint64_t)(x))
+#define cpu_to_be16(x) swab16(x)
+#define cpu_to_be32(x) swab32(x)
+#define cpu_to_be64(x) swab64(x)
+
+#define le16_to_cpu(x) ((uint16_t)(x))
+#define le32_to_cpu(x) ((uint32_t)(x))
+#define le64_to_cpu(x) ((uint64_t)(x))
+#define be16_to_cpu(x) swab16(x)
+#define be32_to_cpu(x) swab32(x)
+#define be64_to_cpu(x) swab64(x)
+
+#endif /* WORDS_BIGENDIAN */
+
+#endif /* BITOPS_H */
#include <inttypes.h>
#include "nls.h"
+#include "bitops.h"
#include "utils_crypt.h"
#include "utils_loop.h"
#include "utils_dm.h"
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 hash_type; /**< in-kernel hashing type */
uint32_t flags; /**< CRYPT_VERITY* flags */
};
r = snprintf(params, max_size,
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s",
- vp->version, dmd->data_device,
+ vp->hash_type, dmd->data_device,
dmd->u.verity.hash_device,
vp->data_block_size, vp->hash_block_size,
vp->data_size, dmd->u.verity.hash_offset,
crypt_safe_free(params);
params = NULL;
}
- log_dbg("TABLE: %s", params);
out:
crypt_safe_free(hexroot);
crypt_safe_free(hexsalt);
if (*params != ' ')
return -EINVAL;
if (vp)
- vp->version = val32;
+ vp->hash_type = val32;
params++;
/* data device */
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 = dmd.u.verity.hash_offset;
- cd->verity_hdr.version = params.version;
+ cd->verity_hdr.hash_type = params.hash_type;
cd->verity_hdr.flags = params.flags;
cd->verity_hdr.salt_size = params.salt_size;
cd->verity_hdr.salt = params.salt;
if (!params || !params->data_device)
return -EINVAL;
- if (params->version > 1)
- return -EINVAL;
-
/* set data device */
cd->type = CRYPT_VERITY;
r = crypt_set_data_device(cd, params->data_device);
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.hash_type = params->hash_type;
cd->verity_hdr.flags = params->flags;
cd->verity_hdr.salt_size = params->salt_size;
cd->verity_hdr.salt = malloc(params->salt_size);
if (requested_type && !isLUKS(requested_type))
return -EINVAL;
- /* Some hash functions need initialized gcrypt library */
r = init_crypto(cd);
if (r < 0)
return r;
struct volume_key *vk = NULL;
int r = -EINVAL;
- log_dbg("Activating volume %s by volume key.", name);
+ log_dbg("Activating volume %s by volume key.", name ?: "[none]");
if (name) {
ci = crypt_status(NULL, name);
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, "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);
log_std(cd, "Hash block size: \t%u\n", cd->verity_hdr.hash_block_size);
vp->hash_block_size = cd->verity_hdr.hash_block_size;
vp->data_size = cd->verity_hdr.data_size;
vp->hash_area_offset = cd->verity_hdr.hash_area_offset;
- vp->version = cd->verity_hdr.version;
+ vp->hash_type = cd->verity_hdr.hash_type;
vp->flags = cd->verity_hdr.flags & CRYPT_VERITY_NO_HEADER;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "verity.h"
#include "internal.h"
-/* FIXME: not yet final on-disk format! Add UUID etc */
+#define NEW_SB 1
+
+#ifndef NEW_SB
struct verity_sb {
uint8_t signature[8];
uint8_t version;
uint32_t data_blocks_hi;
uint32_t data_blocks_lo;
uint8_t algorithm[16];
- uint8_t salt[VERITY_MAX_SALT_SIZE];
+ uint8_t salt[384];
uint8_t pad3[88];
};
+#else
+struct verity_sb {
+ uint8_t signature[8]; /* "verity\0\0" */
+ uint32_t version; /* superblock version */
+ uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */
+ uint8_t uuid[16]; /* UUID of hash device */
+ uint8_t algorithm[32];/* hash algorithm name */
+ uint64_t data_block_size; /* data block in bytes */
+ uint64_t hash_block_size; /* hash block in bytes */
+ uint64_t data_blocks; /* number of data blocks */
+ uint64_t salt_size; /* salt size */
+ uint8_t salt[256]; /* salt */
+ uint8_t _pad[160];
+} __attribute__((packed));
+#endif
+
/* Read verity superblock from disk */
int VERITY_read_sb(struct crypt_device *cd,
const char *device,
{
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
- int devfd = 0;
+ int devfd = 0, sb_version;
uint64_t sb_data_blocks;
log_dbg("Reading VERITY header of size %u on device %s, offset %" PRIu64 ".",
log_err(cd, _("Device %s is not a valid VERITY device.\n"), device);
return -EINVAL;
}
-
+#ifndef NEW_SB
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) {
+ ntohs(sb.salt_size) > 256) {
log_err(cd, _("VERITY header corrupted.\n"));
return -EINVAL;
}
if (!params->salt)
return -ENOMEM;
memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
- params->hash_area_offset = sb_offset;
- params->version = sb.version;
+ params->hash_type = sb.version;
+#else
+ sb_version = le32_to_cpu(sb.version);
+ if (sb_version != 1) {
+ log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version);
+ return -EINVAL;
+ }
+ params->hash_type = le32_to_cpu(sb.hash_type);
+ if (params->hash_type > 1) {
+ log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type);
+ return -EINVAL;
+ }
+ params->data_block_size = le64_to_cpu(sb.data_block_size);
+ params->hash_block_size = le64_to_cpu(sb.hash_block_size);
+ if (params->data_block_size % 512 || params->hash_block_size % 512) {
+ log_err(cd, _("Unsupported VERITY block size.\n"));
+ return -EINVAL;
+ }
+ params->data_size = le64_to_cpu(sb.data_blocks);
+
+ params->hash_name = strndup((const char*)sb.algorithm, sizeof(sb.algorithm));
+ if (!params->hash_name)
+ return -ENOMEM;
+
+ params->salt_size = le64_to_cpu(sb.salt_size);
+ if (params->salt_size > sizeof(sb.salt)) {
+ log_err(cd, _("VERITY header corrupted.\n"));
+ free(CONST_CAST(char*)params->hash_name);
+ return -EINVAL;
+ }
+ params->salt = malloc(params->salt_size);
+ if (!params->salt) {
+ free(CONST_CAST(char*)params->hash_name);
+ return -ENOMEM;
+ }
+ memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size);
+
+#endif
+ params->hash_area_offset = sb_offset;
return 0;
}
}
memcpy(&sb.signature, VERITY_SIGNATURE, sizeof(sb.signature));
- sb.version = params->version;
+#ifndef NEW_SB
+ sb.version = params->hash_type;
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_lo = htonl(params->data_size & 0xFFFFFFFF);
strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm));
memcpy(sb.salt, params->salt, params->salt_size);
-
+#else
+ sb.version = cpu_to_le32(1);
+ sb.hash_type = cpu_to_le32(params->hash_type);
+ sb.data_block_size = cpu_to_le64(params->data_block_size);
+ sb.hash_block_size = cpu_to_le64(params->hash_block_size);
+ sb.salt_size = cpu_to_le64(params->salt_size);
+ 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);
+#endif
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);
#define VERITY_SIGNATURE "verity\0\0"
#define VERITY_MAX_LEVELS 63
-#define VERITY_MAX_SALT_SIZE 384
struct crypt_device;
struct crypt_params_verity;
size_t root_hash_size)
{
return VERITY_create_or_verify_hash(cd, 1,
- verity_hdr->version,
+ verity_hdr->hash_type,
verity_hdr->hash_name,
hash_device,
data_device,
{
int pgsize = crypt_getpagesize();
- if (verity_hdr->salt_size > VERITY_MAX_SALT_SIZE)
+ if (verity_hdr->salt_size > 256)
return -EINVAL;
if (verity_hdr->hash_block_size > pgsize ||
"size exceeds page size (%u).\n"), pgsize);
return VERITY_create_or_verify_hash(cd, 0,
- verity_hdr->version,
+ verity_hdr->hash_type,
verity_hdr->hash_name,
hash_device,
data_device,
/* TODO:
* - extend superblock (UUID)
* - add api tests
- * - report in-kernel status outside libcryptsetup (extend api)
*/
#include <stdio.h>
static int use_superblock = 1; /* FIXME: no superblock not supported */
static const char *hash_algorithm = NULL;
-static int version = 1;
+static int hash_type = 1;
static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
static uint64_t data_blocks = 0;
params->hash_block_size = hash_block_size;
params->data_size = data_blocks;
params->hash_area_offset = hash_start;
- params->version = version;
+ params->hash_type = hash_type;
params->flags = flags;
return 0;
if (r < 0)
goto out;
- log_std(" version: %u\n", vp.version);
+ log_std(" hash type: %u\n", vp.hash_type);
log_std(" data block: %u\n", vp.data_block_size);
log_std(" hash block: %u\n", vp.hash_block_size);
log_std(" hash name: %s\n", vp.hash_name);
{ "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
{ "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
{ "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, N_("Do not use verity superblock"), NULL },
- { "format", 0, POPT_ARG_INT, &version, 0, N_("Format type (1 - normal, 0 - original Chromium OS)"), N_("number") },
+ { "format", 0, POPT_ARG_INT, &hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
{ "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
{ "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
{ "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") },