"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/setup.c" between
cryptsetup-2.0.6.tar.xz and cryptsetup-2.1.0.tar.xz

About: cryptsetup is a utility used to conveniently setup disk encryption based on the dm-crypt kernel module. These include plain dm-crypt volumes, LUKS volumes, loop-AES and TrueCrypt compatible format.

setup.c  (cryptsetup-2.0.6.tar.xz):setup.c  (cryptsetup-2.1.0.tar.xz)
/* /*
* libcryptsetup - cryptsetup library * libcryptsetup - cryptsetup library
* *
* Copyright (C) 2004, Jana Saout <jana@saout.de> * Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org> * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved. * Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz * Copyright (C) 2009-2019 Milan Broz
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
skipping to change at line 57 skipping to change at line 57
struct device *device; struct device *device;
struct device *metadata_device; struct device *metadata_device;
struct volume_key *volume_key; struct volume_key *volume_key;
int rng_type; int rng_type;
struct crypt_pbkdf_type pbkdf; struct crypt_pbkdf_type pbkdf;
/* global context scope settings */ /* global context scope settings */
unsigned key_in_keyring:1; unsigned key_in_keyring:1;
uint64_t data_offset;
uint64_t metadata_size; /* Used in LUKS2 format */
uint64_t keyslots_size; /* Used in LUKS2 format */
// FIXME: private binary headers and access it properly // FIXME: private binary headers and access it properly
// through sub-library (LUKS1, TCRYPT) // through sub-library (LUKS1, TCRYPT)
union { union {
struct { /* used in CRYPT_LUKS1 */ struct { /* used in CRYPT_LUKS1 */
struct luks_phdr hdr; struct luks_phdr hdr;
char *cipher_spec;
} luks1; } luks1;
struct { /* used in CRYPT_LUKS2 */ struct { /* used in CRYPT_LUKS2 */
struct luks2_hdr hdr; struct luks2_hdr hdr;
char *cipher; /* only for compatibility, segment 0 */ char cipher[MAX_CIPHER_LEN]; /* only for compatibility */
char *cipher_mode; /* only for compatibility, segment 0 */ char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
char *keyslot_cipher;
unsigned int keyslot_key_size;
} luks2; } luks2;
struct { /* used in CRYPT_PLAIN */ struct { /* used in CRYPT_PLAIN */
struct crypt_params_plain hdr; struct crypt_params_plain hdr;
char *cipher_spec;
char *cipher; char *cipher;
char *cipher_mode; const char *cipher_mode;
unsigned int key_size; unsigned int key_size;
} plain; } plain;
struct { /* used in CRYPT_LOOPAES */ struct { /* used in CRYPT_LOOPAES */
struct crypt_params_loopaes hdr; struct crypt_params_loopaes hdr;
char *cipher_spec;
char *cipher; char *cipher;
char *cipher_mode; const char *cipher_mode;
unsigned int key_size; unsigned int key_size;
} loopaes; } loopaes;
struct { /* used in CRYPT_VERITY */ struct { /* used in CRYPT_VERITY */
struct crypt_params_verity hdr; struct crypt_params_verity hdr;
char *root_hash; char *root_hash;
unsigned int root_hash_size; unsigned int root_hash_size;
char *uuid; char *uuid;
struct device *fec_device; struct device *fec_device;
} verity; } verity;
struct { /* used in CRYPT_TCRYPT */ struct { /* used in CRYPT_TCRYPT */
skipping to change at line 100 skipping to change at line 109
struct tcrypt_phdr hdr; struct tcrypt_phdr hdr;
} tcrypt; } tcrypt;
struct { /* used in CRYPT_INTEGRITY */ struct { /* used in CRYPT_INTEGRITY */
struct crypt_params_integrity params; struct crypt_params_integrity params;
struct volume_key *journal_mac_key; struct volume_key *journal_mac_key;
struct volume_key *journal_crypt_key; struct volume_key *journal_crypt_key;
} integrity; } integrity;
struct { /* used if initialized without header by name */ struct { /* used if initialized without header by name */
char *active_name; char *active_name;
/* buffers, must refresh from kernel on every query */ /* buffers, must refresh from kernel on every query */
char cipher_spec[MAX_CIPHER_LEN*2+1];
char cipher[MAX_CIPHER_LEN]; char cipher[MAX_CIPHER_LEN];
char cipher_mode[MAX_CIPHER_LEN]; const char *cipher_mode;
unsigned int key_size; unsigned int key_size;
unsigned int veracrypt_pim;
} none; } none;
} u; } u;
/* callbacks definitions */ /* callbacks definitions */
void (*log)(int level, const char *msg, void *usrptr); void (*log)(int level, const char *msg, void *usrptr);
void *log_usrptr; void *log_usrptr;
int (*confirm)(const char *msg, void *usrptr); int (*confirm)(const char *msg, void *usrptr);
void *confirm_usrptr; void *confirm_usrptr;
}; };
skipping to change at line 144 skipping to change at line 153
int crypt_get_debug_level(void) int crypt_get_debug_level(void)
{ {
return _debug_level; return _debug_level;
} }
void crypt_log(struct crypt_device *cd, int level, const char *msg) void crypt_log(struct crypt_device *cd, int level, const char *msg)
{ {
if (!msg) if (!msg)
return; return;
if (level < _debug_level)
return;
if (cd && cd->log) if (cd && cd->log)
cd->log(level, msg, cd->log_usrptr); cd->log(level, msg, cd->log_usrptr);
else if (_default_log) else if (_default_log)
_default_log(level, msg, NULL); _default_log(level, msg, NULL);
else if (_debug_level) /* Default to stdout/stderr if there is no callback. */
printf("%s", msg); else
fprintf(level == CRYPT_LOG_ERROR ? stderr : stdout, "%s", msg);
} }
__attribute__((format(printf, 5, 6))) __attribute__((format(printf, 5, 6)))
void logger(struct crypt_device *cd, int level, const char *file, void logger(struct crypt_device *cd, int level, const char *file,
int line, const char *format, ...) int line, const char *format, ...)
{ {
va_list argp; va_list argp;
char target[LOG_MAX_LEN + 2]; char target[LOG_MAX_LEN + 2];
va_start(argp, format); va_start(argp, format);
if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0 ) { if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0 ) {
if (level >= 0) { /* All verbose and error messages in tools end with EOL. */
/* All verbose and error messages in tools end with EOL. if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR)
*/ strncat(target, "\n", LOG_MAX_LEN);
if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERRO
R) crypt_log(cd, level, target);
strncat(target, "\n", LOG_MAX_LEN);
crypt_log(cd, level, target);
#ifdef CRYPT_DEBUG
} else if (_debug_level)
printf("# %s:%d %s\n", file ?: "?", line, target);
#else
} else if (_debug_level)
printf("# %s\n", target);
#endif
} }
va_end(argp); va_end(argp);
} }
static const char *mdata_device_path(struct crypt_device *cd) static const char *mdata_device_path(struct crypt_device *cd)
{ {
return device_path(cd->metadata_device ?: cd->device); return device_path(cd->metadata_device ?: cd->device);
} }
skipping to change at line 217 skipping to change at line 223
if (r < 0) { if (r < 0) {
log_err(ctx, _("Cannot initialize crypto RNG backend.")); log_err(ctx, _("Cannot initialize crypto RNG backend."));
return r; return r;
} }
r = crypt_backend_init(ctx); r = crypt_backend_init(ctx);
if (r < 0) if (r < 0)
log_err(ctx, _("Cannot initialize crypto backend.")); log_err(ctx, _("Cannot initialize crypto backend."));
if (!r && !_crypto_logged) { if (!r && !_crypto_logged) {
log_dbg("Crypto backend (%s) initialized in cryptsetup library ve rsion %s.", log_dbg(ctx, "Crypto backend (%s) initialized in cryptsetup libra ry version %s.",
crypt_backend_version(), PACKAGE_VERSION); crypt_backend_version(), PACKAGE_VERSION);
if (!uname(&uts)) if (!uname(&uts))
log_dbg("Detected kernel %s %s %s.", log_dbg(ctx, "Detected kernel %s %s %s.",
uts.sysname, uts.release, uts.machine); uts.sysname, uts.release, uts.machine);
_crypto_logged = 1; _crypto_logged = 1;
} }
return r; return r;
} }
static int process_key(struct crypt_device *cd, const char *hash_name, static int process_key(struct crypt_device *cd, const char *hash_name,
size_t key_size, const char *pass, size_t passLen, size_t key_size, const char *pass, size_t passLen,
struct volume_key **vk) struct volume_key **vk)
skipping to change at line 365 skipping to change at line 371
} }
static void crypt_set_null_type(struct crypt_device *cd) static void crypt_set_null_type(struct crypt_device *cd)
{ {
if (!cd->type) if (!cd->type)
return; return;
free(cd->type); free(cd->type);
cd->type = NULL; cd->type = NULL;
cd->u.none.active_name = NULL; cd->u.none.active_name = NULL;
cd->data_offset = 0;
cd->metadata_size = 0;
cd->keyslots_size = 0;
} }
static void crypt_reset_null_type(struct crypt_device *cd) static void crypt_reset_null_type(struct crypt_device *cd)
{ {
if (cd->type) if (cd->type)
return; return;
free(cd->u.none.active_name); free(cd->u.none.active_name);
cd->u.none.active_name = NULL; cd->u.none.active_name = NULL;
} }
skipping to change at line 409 skipping to change at line 418
*keyslot, LUKS_NUMKEYS - 1); *keyslot, LUKS_NUMKEYS - 1);
return -EINVAL; return -EINVAL;
case CRYPT_SLOT_INACTIVE: case CRYPT_SLOT_INACTIVE:
break; break;
default: default:
log_err(cd, _("Key slot %d is full, please select another one."), log_err(cd, _("Key slot %d is full, please select another one."),
*keyslot); *keyslot);
return -EINVAL; return -EINVAL;
} }
log_dbg("Selected keyslot %d.", *keyslot); log_dbg(cd, "Selected keyslot %d.", *keyslot);
return 0; return 0;
} }
/* /*
* compares UUIDs returned by device-mapper (striped by cryptsetup) and uuid in header * compares UUIDs returned by device-mapper (striped by cryptsetup) and uuid in header
*/ */
static int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid) static int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid)
{ {
int i, j; int i, j;
char *str; char *str;
skipping to change at line 448 skipping to change at line 457
} }
return 0; return 0;
} }
/* /*
* compares type of active device to provided string (only if there is no explic it type) * compares type of active device to provided string (only if there is no explic it type)
*/ */
static int crypt_uuid_type_cmp(struct crypt_device *cd, const char *type) static int crypt_uuid_type_cmp(struct crypt_device *cd, const char *type)
{ {
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd;
size_t len; size_t len;
int r; int r;
/* Must user header-on-disk if we know type here */ /* Must user header-on-disk if we know type here */
if (cd->type || !cd->u.none.active_name) if (cd->type || !cd->u.none.active_name)
return -EINVAL; return -EINVAL;
log_dbg("Checking if active device %s without header has UUID type %s.", log_dbg(cd, "Checking if active device %s without header has UUID type %s .",
cd->u.none.active_name, type); cd->u.none.active_name, type);
r = dm_query_device(cd, cd->u.none.active_name, DM_ACTIVE_UUID, &dmd); r = dm_query_device(cd, cd->u.none.active_name, DM_ACTIVE_UUID, &dmd);
if (r < 0) if (r < 0)
return r; return r;
r = -ENODEV; r = -ENODEV;
len = strlen(type); len = strlen(type);
if (dmd.uuid && strlen(dmd.uuid) > len && if (dmd.uuid && strlen(dmd.uuid) > len &&
!strncmp(dmd.uuid, type, len) && dmd.uuid[len] == '-') !strncmp(dmd.uuid, type, len) && dmd.uuid[len] == '-')
skipping to change at line 480 skipping to change at line 489
return r; return r;
} }
int PLAIN_activate(struct crypt_device *cd, int PLAIN_activate(struct crypt_device *cd,
const char *name, const char *name,
struct volume_key *vk, struct volume_key *vk,
uint64_t size, uint64_t size,
uint32_t flags) uint32_t flags)
{ {
int r; int r;
char *dm_cipher = NULL;
enum devcheck device_check;
struct crypt_dm_active_device dmd = { struct crypt_dm_active_device dmd = {
.target = DM_CRYPT, .flags = flags,
.size = size, .size = size,
.flags = flags,
.data_device = crypt_data_device(cd),
.u.crypt = {
.cipher = NULL,
.vk = vk,
.offset = crypt_get_data_offset(cd),
.iv_offset = crypt_get_iv_offset(cd),
.sector_size = crypt_get_sector_size(cd),
}
}; };
if (dmd.flags & CRYPT_ACTIVATE_SHARED) log_dbg(cd, "Trying to activate PLAIN device %s using cipher %s.",
device_check = DEV_SHARED; name, crypt_get_cipher_spec(cd));
else
device_check = DEV_EXCL;
r = device_block_adjust(cd, dmd.data_device, device_check, r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
dmd.u.crypt.offset, &dmd.size, &dmd.flags); vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd),
if (r) crypt_get_data_offset(cd), crypt_get_integrity(cd),
return r; crypt_get_integrity_tag_size(cd), crypt_get_sector_size(c
d));
if (crypt_get_cipher_mode(cd))
r = asprintf(&dm_cipher, "%s-%s", crypt_get_cipher(cd), crypt_get
_cipher_mode(cd));
else
r = asprintf(&dm_cipher, "%s", crypt_get_cipher(cd));
if (r < 0) if (r < 0)
return -ENOMEM; return r;
dmd.u.crypt.cipher = dm_cipher;
log_dbg("Trying to activate PLAIN device %s using cipher %s.",
name, dmd.u.crypt.cipher);
r = dm_create_device(cd, name, CRYPT_PLAIN, &dmd, 0); r = create_or_reload_device(cd, name, CRYPT_PLAIN, &dmd);
free(dm_cipher); dm_targets_free(cd, &dmd);
return r; return r;
} }
int crypt_confirm(struct crypt_device *cd, const char *msg) int crypt_confirm(struct crypt_device *cd, const char *msg)
{ {
if (!cd || !cd->confirm) if (!cd || !cd->confirm)
return 1; return 1;
else else
return cd->confirm(msg, cd->confirm_usrptr); return cd->confirm(msg, cd->confirm_usrptr);
} }
skipping to change at line 566 skipping to change at line 553
} }
int crypt_init(struct crypt_device **cd, const char *device) int crypt_init(struct crypt_device **cd, const char *device)
{ {
struct crypt_device *h = NULL; struct crypt_device *h = NULL;
int r; int r;
if (!cd) if (!cd)
return -EINVAL; return -EINVAL;
log_dbg("Allocating context for crypt device %s.", device ?: "(none)"); log_dbg(NULL, "Allocating context for crypt device %s.", device ?: "(none )");
if (!(h = malloc(sizeof(struct crypt_device)))) if (!(h = malloc(sizeof(struct crypt_device))))
return -ENOMEM; return -ENOMEM;
memset(h, 0, sizeof(*h)); memset(h, 0, sizeof(*h));
r = device_alloc(&h->device, device); r = device_alloc(NULL, &h->device, device);
if (r < 0) if (r < 0)
goto bad; goto bad;
dm_backend_init(); dm_backend_init(NULL);
h->rng_type = crypt_random_default_key_rng(); h->rng_type = crypt_random_default_key_rng();
*cd = h; *cd = h;
return 0; return 0;
bad: bad:
device_free(h->device); device_free(NULL, h->device);
free(h); free(h);
return r; return r;
} }
static int crypt_check_data_device_size(struct crypt_device *cd) static int crypt_check_data_device_size(struct crypt_device *cd)
{ {
int r; int r;
uint64_t size, size_min; uint64_t size, size_min;
/* Check data device size, require at least header or one sector */ /* Check data device size, require at least header or one sector */
skipping to change at line 610 skipping to change at line 597
if (size < size_min) { if (size < size_min) {
log_err(cd, _("Header detected but device %s is too small."), log_err(cd, _("Header detected but device %s is too small."),
device_path(cd->device)); device_path(cd->device));
return -EINVAL; return -EINVAL;
} }
return r; return r;
} }
int crypt_set_data_device(struct crypt_device *cd, const char *device) static int _crypt_set_data_device(struct crypt_device *cd, const char *device)
{ {
struct device *dev = NULL; struct device *dev = NULL;
int r; int r;
if (!cd) r = device_alloc(cd, &dev, device);
if (r < 0)
return r;
if (!cd->metadata_device) {
cd->metadata_device = cd->device;
} else
device_free(cd, cd->device);
cd->device = dev;
return crypt_check_data_device_size(cd);
}
int crypt_set_data_device(struct crypt_device *cd, const char *device)
{
/* metadata device must be set */
if (!cd || !cd->device || !device)
return -EINVAL; return -EINVAL;
log_dbg("Setting ciphertext data device to %s.", device ?: "(none)"); log_dbg(cd, "Setting ciphertext data device to %s.", device ?: "(none)");
if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type)) { if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
!isINTEGRITY(cd->type)) {
log_err(cd, _("This operation is not supported for this device ty pe.")); log_err(cd, _("This operation is not supported for this device ty pe."));
return -EINVAL; return -EINVAL;
} }
/* metadata device must be set */ return _crypt_set_data_device(cd, device);
if (!cd->device || !device) }
int crypt_init_data_device(struct crypt_device **cd, const char *device, const c
har *data_device)
{
int r;
if (!cd)
return -EINVAL; return -EINVAL;
r = device_alloc(&dev, device); r = crypt_init(cd, device);
if (r < 0) if (r || !data_device)
return r; return r;
if (!cd->metadata_device) { log_dbg(NULL, "Setting ciphertext data device to %s.", data_device ?: "(n
cd->metadata_device = cd->device; one)");
} else r = _crypt_set_data_device(*cd, data_device);
device_free(cd->device); if (r)
crypt_free(*cd);
cd->device = dev;
return crypt_check_data_device_size(cd); return r;
} }
/* internal only */ /* internal only */
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd) struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd)
{ {
return &cd->pbkdf; return &cd->pbkdf;
} }
/* /*
* crypt_load() helpers * crypt_load() helpers
*/ */
static int _crypt_load_luks2(struct crypt_device *cd, int reload, int repair) static int _crypt_load_luks2(struct crypt_device *cd, int reload, int repair)
{ {
int r; int r;
char tmp_cipher[MAX_CIPHER_LEN], tmp_cipher_mode[MAX_CIPHER_LEN], char *type = NULL;
*cipher = NULL, *cipher_mode = NULL, *type = NULL;
struct luks2_hdr hdr2 = {}; struct luks2_hdr hdr2 = {};
log_dbg("%soading LUKS2 header (repair %sabled).", reload ? "Rel" : "L", repair ? "en" : "dis"); log_dbg(cd, "%soading LUKS2 header (repair %sabled).", reload ? "Rel" : " L", repair ? "en" : "dis");
r = LUKS2_hdr_read(cd, &hdr2, repair); r = LUKS2_hdr_read(cd, &hdr2, repair);
if (r) if (r)
return r; return r;
if (!reload && !(type = strdup(CRYPT_LUKS2))) { if (!reload && !(type = strdup(CRYPT_LUKS2))) {
r = -ENOMEM; r = -ENOMEM;
goto out; goto out;
} }
r = crypt_parse_name_and_mode(LUKS2_get_cipher(&hdr2, CRYPT_DEFAULT_SEGME
NT),
tmp_cipher, NULL, tmp_cipher_mode);
if (r < 0) {
log_dbg("Cannot parse cipher and mode from loaded device.");
goto out;
}
cipher = strdup(tmp_cipher);
cipher_mode = strdup(tmp_cipher_mode);
if (!cipher || !cipher_mode) {
r = -ENOMEM;
goto out;
}
if (verify_pbkdf_params(cd, &cd->pbkdf)) { if (verify_pbkdf_params(cd, &cd->pbkdf)) {
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS2); r = init_pbkdf_type(cd, NULL, CRYPT_LUKS2);
if (r) if (r)
goto out; goto out;
} }
if (reload) { if (reload)
LUKS2_hdr_free(&cd->u.luks2.hdr); LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.cipher); else
free(cd->u.luks2.cipher_mode);
} else
cd->type = type; cd->type = type;
r = 0; r = 0;
memcpy(&cd->u.luks2.hdr, &hdr2, sizeof(hdr2)); memcpy(&cd->u.luks2.hdr, &hdr2, sizeof(hdr2));
cd->u.luks2.keyslot_cipher = NULL;
/* Save cipher and mode, compatibility only. */
cd->u.luks2.cipher = cipher;
cd->u.luks2.cipher_mode = cipher_mode;
out: out:
if (r) { if (r) {
free(cipher);
free(cipher_mode);
free(type); free(type);
LUKS2_hdr_free(&hdr2); LUKS2_hdr_free(cd, &hdr2);
} }
/* FIXME: why? */ /* FIXME: why? */
crypt_memzero(&hdr2, sizeof(hdr2)); crypt_memzero(&hdr2, sizeof(hdr2));
return r; return r;
} }
static void _luks2_reload(struct crypt_device *cd) static void _luks2_reload(struct crypt_device *cd)
{ {
if (!cd || !isLUKS2(cd->type)) if (!cd || !isLUKS2(cd->type))
return; return;
(void) _crypt_load_luks2(cd, 1, 0); (void) _crypt_load_luks2(cd, 1, 0);
} }
static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type, static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type,
int require_header, int repair) int require_header, int repair)
{ {
char *cipher_spec;
struct luks_phdr hdr = {}; struct luks_phdr hdr = {};
int r, version = 0; int r, version;
r = init_crypto(cd); r = init_crypto(cd);
if (r < 0) if (r < 0)
return r; return r;
/* This will return 0 if primary LUKS2 header is damaged */ /* This will return 0 if primary LUKS2 header is damaged */
if (!requested_type) version = LUKS2_hdr_version_unlocked(cd, NULL);
version = LUKS2_hdr_version_unlocked(cd, NULL);
if ((isLUKS1(requested_type) && version == 2) ||
(isLUKS2(requested_type) && version == 1))
return -EINVAL;
if (requested_type)
version = 0;
if (isLUKS1(requested_type) || version == 1) { if (isLUKS1(requested_type) || version == 1) {
if (cd->type && isLUKS2(cd->type)) { if (cd->type && isLUKS2(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
if (verify_pbkdf_params(cd, &cd->pbkdf)) { if (verify_pbkdf_params(cd, &cd->pbkdf)) {
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1); r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1);
if (r) if (r)
return r; return r;
} }
r = LUKS_read_phdr(&hdr, require_header, repair, cd); r = LUKS_read_phdr(&hdr, require_header, repair, cd);
skipping to change at line 769 skipping to change at line 764
/* Set hash to the same as in the loaded header */ /* Set hash to the same as in the loaded header */
if (!cd->pbkdf.hash || strcmp(cd->pbkdf.hash, hdr.hashSpec)) { if (!cd->pbkdf.hash || strcmp(cd->pbkdf.hash, hdr.hashSpec)) {
free(CONST_CAST(void*)cd->pbkdf.hash); free(CONST_CAST(void*)cd->pbkdf.hash);
cd->pbkdf.hash = strdup(hdr.hashSpec); cd->pbkdf.hash = strdup(hdr.hashSpec);
if (!cd->pbkdf.hash) { if (!cd->pbkdf.hash) {
r = -ENOMEM; r = -ENOMEM;
goto out; goto out;
} }
} }
if (asprintf(&cipher_spec, "%s-%s", hdr.cipherName, hdr.cipherMod
e) < 0) {
r = -ENOMEM;
goto out;
}
free(cd->u.luks1.cipher_spec);
cd->u.luks1.cipher_spec = cipher_spec;
memcpy(&cd->u.luks1.hdr, &hdr, sizeof(hdr)); memcpy(&cd->u.luks1.hdr, &hdr, sizeof(hdr));
} else if (isLUKS2(requested_type) || version == 2 || version == 0) { } else if (isLUKS2(requested_type) || version == 2 || version == 0) {
if (cd->type && isLUKS1(cd->type)) { if (cd->type && isLUKS1(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
/* /*
* Current LUKS2 repair just overrides blkid probes * Current LUKS2 repair just overrides blkid probes
* and perform auto-recovery if possible. This is safe * and perform auto-recovery if possible. This is safe
* unless future LUKS2 repair code do something more * unless future LUKS2 repair code do something more
* sophisticated. In such case we would need to check * sophisticated. In such case we would need to check
* for LUKS2 requirements and decide if it's safe to * for LUKS2 requirements and decide if it's safe to
* perform repair. * perform repair.
skipping to change at line 803 skipping to change at line 806
return r; return r;
} }
static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp t *params) static int _crypt_load_tcrypt(struct crypt_device *cd, struct crypt_params_tcryp t *params)
{ {
int r; int r;
if (!params) if (!params)
return -EINVAL; return -EINVAL;
if (cd->metadata_device) {
log_err(cd, _("Detached metadata device is not supported for this
crypt type."));
return -EINVAL;
}
r = init_crypto(cd); r = init_crypto(cd);
if (r < 0) if (r < 0)
return r; return r;
memcpy(&cd->u.tcrypt.params, params, sizeof(*params)); memcpy(&cd->u.tcrypt.params, params, sizeof(*params));
r = TCRYPT_read_phdr(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params); r = TCRYPT_read_phdr(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
cd->u.tcrypt.params.passphrase = NULL; cd->u.tcrypt.params.passphrase = NULL;
cd->u.tcrypt.params.passphrase_size = 0; cd->u.tcrypt.params.passphrase_size = 0;
skipping to change at line 867 skipping to change at line 875
/* Hash availability checked in sb load */ /* Hash availability checked in sb load */
cd->u.verity.root_hash_size = crypt_hash_size(cd->u.verity.hdr.hash_name) ; cd->u.verity.root_hash_size = crypt_hash_size(cd->u.verity.hdr.hash_name) ;
if (cd->u.verity.root_hash_size > 4096) if (cd->u.verity.root_hash_size > 4096)
return -EINVAL; return -EINVAL;
if (params && params->data_device && if (params && params->data_device &&
(r = crypt_set_data_device(cd, params->data_device)) < 0) (r = crypt_set_data_device(cd, params->data_device)) < 0)
return r; return r;
if (params && params->fec_device) { if (params && params->fec_device) {
r = device_alloc(&cd->u.verity.fec_device, params->fec_device); r = device_alloc(cd, &cd->u.verity.fec_device, params->fec_device );
if (r < 0) if (r < 0)
return r; return r;
cd->u.verity.hdr.fec_area_offset = params->fec_area_offset; cd->u.verity.hdr.fec_area_offset = params->fec_area_offset;
cd->u.verity.hdr.fec_roots = params->fec_roots; cd->u.verity.hdr.fec_roots = params->fec_roots;
} }
return r; return r;
} }
static int _crypt_load_integrity(struct crypt_device *cd, static int _crypt_load_integrity(struct crypt_device *cd,
skipping to change at line 938 skipping to change at line 946
int crypt_load(struct crypt_device *cd, int crypt_load(struct crypt_device *cd,
const char *requested_type, const char *requested_type,
void *params) void *params)
{ {
int r; int r;
if (!cd) if (!cd)
return -EINVAL; return -EINVAL;
log_dbg("Trying to load %s crypt type from device %s.", log_dbg(cd, "Trying to load %s crypt type from device %s.",
requested_type ?: "any", mdata_device_path(cd) ?: "(none)"); requested_type ?: "any", mdata_device_path(cd) ?: "(none)");
if (!crypt_metadata_device(cd)) if (!crypt_metadata_device(cd))
return -EINVAL; return -EINVAL;
crypt_reset_null_type(cd); crypt_reset_null_type(cd);
cd->data_offset = 0;
cd->metadata_size = 0;
cd->keyslots_size = 0;
if (!requested_type || isLUKS1(requested_type) || isLUKS2(requested_type) ) { if (!requested_type || isLUKS1(requested_type) || isLUKS2(requested_type) ) {
if (cd->type && !isLUKS1(cd->type) && !isLUKS2(cd->type)) { if (cd->type && !isLUKS1(cd->type) && !isLUKS2(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
r = _crypt_load_luks(cd, requested_type, 1, 0); r = _crypt_load_luks(cd, requested_type, 1, 0);
} else if (isVERITY(requested_type)) { } else if (isVERITY(requested_type)) {
if (cd->type && !isVERITY(cd->type)) { if (cd->type && !isVERITY(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
r = _crypt_load_verity(cd, params); r = _crypt_load_verity(cd, params);
} else if (isTCRYPT(requested_type)) { } else if (isTCRYPT(requested_type)) {
if (cd->type && !isTCRYPT(cd->type)) { if (cd->type && !isTCRYPT(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
r = _crypt_load_tcrypt(cd, params); r = _crypt_load_tcrypt(cd, params);
} else if (isINTEGRITY(requested_type)) { } else if (isINTEGRITY(requested_type)) {
if (cd->type && !isINTEGRITY(cd->type)) { if (cd->type && !isINTEGRITY(cd->type)) {
log_dbg("Context is already initialised to type %s", cd-> type); log_dbg(cd, "Context is already initialised to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
r = _crypt_load_integrity(cd, params); r = _crypt_load_integrity(cd, params);
} else } else
return -EINVAL; return -EINVAL;
return r; return r;
} }
/* /*
* crypt_init() helpers * crypt_init() helpers
*/ */
static int _init_by_name_crypt_none(struct crypt_device *cd) static int _init_by_name_crypt_none(struct crypt_device *cd)
{ {
struct crypt_dm_active_device dmd = {};
int r; int r;
char _mode[MAX_CIPHER_LEN];
struct crypt_dm_active_device dmd;
struct dm_target *tgt = &dmd.segment;
if (cd->type || !cd->u.none.active_name) if (cd->type || !cd->u.none.active_name)
return -EINVAL; return -EINVAL;
r = dm_query_device(cd, cd->u.none.active_name, r = dm_query_device(cd, cd->u.none.active_name,
DM_ACTIVE_CRYPT_CIPHER | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_CRYPT_KEYSIZE, &dmd); DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
if (r < 0)
return r;
if (!single_segment(&dmd) || tgt->type != DM_CRYPT)
r = -EINVAL;
if (r >= 0) if (r >= 0)
r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, r = crypt_parse_name_and_mode(tgt->u.crypt.cipher,
cd->u.none.cipher, NULL, cd->u.none.cipher, NULL,
cd->u.none.cipher_mode); _mode);
if (!r) if (!r) {
cd->u.none.key_size = dmd.u.crypt.vk->keylength; snprintf(cd->u.none.cipher_spec, sizeof(cd->u.none.cipher_spec),
"%s-%s", cd->u.none.cipher, _mode);
cd->u.none.cipher_mode = cd->u.none.cipher_spec + strlen(cd->u.no
ne.cipher) + 1;
cd->u.none.key_size = tgt->u.crypt.vk->keylength;
}
crypt_free_volume_key(dmd.u.crypt.vk); dm_targets_free(cd, &dmd);
free(CONST_CAST(void*)dmd.u.crypt.cipher);
free(CONST_CAST(void*)dmd.u.crypt.integrity);
return r; return r;
} }
static const char *LUKS_UUID(struct crypt_device *cd) static const char *LUKS_UUID(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return NULL; return NULL;
else if (isLUKS1(cd->type)) else if (isLUKS1(cd->type))
return cd->u.luks1.hdr.uuid; return cd->u.luks1.hdr.uuid;
else if (isLUKS2(cd->type)) else if (isLUKS2(cd->type))
return cd->u.luks2.hdr.uuid; return cd->u.luks2.hdr.uuid;
return NULL; return NULL;
} }
static void crypt_free_type(struct crypt_device *cd) static void crypt_free_type(struct crypt_device *cd)
{ {
if (isPLAIN(cd->type)) { if (isPLAIN(cd->type)) {
free(CONST_CAST(void*)cd->u.plain.hdr.hash); free(CONST_CAST(void*)cd->u.plain.hdr.hash);
free(cd->u.plain.cipher); free(cd->u.plain.cipher);
free(cd->u.plain.cipher_mode); free(cd->u.plain.cipher_spec);
} else if (isLUKS2(cd->type)) { } else if (isLUKS2(cd->type)) {
LUKS2_hdr_free(&cd->u.luks2.hdr); LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.cipher); free(cd->u.luks2.keyslot_cipher);
free(cd->u.luks2.cipher_mode); } else if (isLUKS1(cd->type)) {
free(cd->u.luks1.cipher_spec);
} else if (isLOOPAES(cd->type)) { } else if (isLOOPAES(cd->type)) {
free(CONST_CAST(void*)cd->u.loopaes.hdr.hash); free(CONST_CAST(void*)cd->u.loopaes.hdr.hash);
free(cd->u.loopaes.cipher); free(cd->u.loopaes.cipher);
free(cd->u.loopaes.cipher_spec);
} else if (isVERITY(cd->type)) { } else if (isVERITY(cd->type)) {
free(CONST_CAST(void*)cd->u.verity.hdr.hash_name); free(CONST_CAST(void*)cd->u.verity.hdr.hash_name);
free(CONST_CAST(void*)cd->u.verity.hdr.data_device); free(CONST_CAST(void*)cd->u.verity.hdr.data_device);
free(CONST_CAST(void*)cd->u.verity.hdr.hash_device); free(CONST_CAST(void*)cd->u.verity.hdr.hash_device);
free(CONST_CAST(void*)cd->u.verity.hdr.fec_device); free(CONST_CAST(void*)cd->u.verity.hdr.fec_device);
free(CONST_CAST(void*)cd->u.verity.hdr.salt); free(CONST_CAST(void*)cd->u.verity.hdr.salt);
free(cd->u.verity.root_hash); free(cd->u.verity.root_hash);
free(cd->u.verity.uuid); free(cd->u.verity.uuid);
device_free(cd->u.verity.fec_device); device_free(cd, cd->u.verity.fec_device);
} else if (isINTEGRITY(cd->type)) { } else if (isINTEGRITY(cd->type)) {
free(CONST_CAST(void*)cd->u.integrity.params.integrity); free(CONST_CAST(void*)cd->u.integrity.params.integrity);
free(CONST_CAST(void*)cd->u.integrity.params.journal_integrity); free(CONST_CAST(void*)cd->u.integrity.params.journal_integrity);
free(CONST_CAST(void*)cd->u.integrity.params.journal_crypt); free(CONST_CAST(void*)cd->u.integrity.params.journal_crypt);
crypt_free_volume_key(cd->u.integrity.journal_crypt_key); crypt_free_volume_key(cd->u.integrity.journal_crypt_key);
crypt_free_volume_key(cd->u.integrity.journal_mac_key); crypt_free_volume_key(cd->u.integrity.journal_mac_key);
} else if (!cd->type) { } else if (!cd->type) {
free(cd->u.none.active_name); free(cd->u.none.active_name);
cd->u.none.active_name = NULL; cd->u.none.active_name = NULL;
} }
crypt_set_null_type(cd); crypt_set_null_type(cd);
} }
static int _init_by_name_crypt(struct crypt_device *cd, const char *name) static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
{ {
struct crypt_dm_active_device dmd = {}, dmdi = {}; char *cipher_spec = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; LEN];
const char *namei; const char *namei;
int key_nums, r; int key_nums, r;
struct crypt_dm_active_device dmd, dmdi = {};
struct dm_target *tgt = &dmd.segment, *tgti = &dmdi.segment;
r = dm_query_device(cd, name, r = dm_query_device(cd, name,
DM_ACTIVE_DEVICE | DM_ACTIVE_DEVICE |
DM_ACTIVE_UUID | DM_ACTIVE_UUID |
DM_ACTIVE_CRYPT_CIPHER | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_CRYPT_KEYSIZE, &dmd); DM_ACTIVE_CRYPT_KEYSIZE, &dmd);
if (r < 0) if (r < 0)
return r;
if (!single_segment(&dmd) || tgt->type != DM_CRYPT) {
log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out; goto out;
}
r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, cipher, r = crypt_parse_name_and_mode(tgt->u.crypt.cipher, cipher,
&key_nums, cipher_mode); &key_nums, cipher_mode);
if (r < 0) { if (r < 0) {
log_dbg("Cannot parse cipher and mode from active device."); log_dbg(cd, "Cannot parse cipher and mode from active device.");
goto out; goto out;
} }
if (dmd.u.crypt.integrity && (namei = device_dm_name(dmd.data_device))) { if (tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi); r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
if (r < 0) if (r < 0)
goto out; goto out;
if (dmdi.target == DM_INTEGRITY && !cd->metadata_device) { if (!single_segment(&dmdi) || tgti->type != DM_INTEGRITY) {
device_free(cd->device); log_dbg(cd, "Unsupported device table detected in %s.", n
cd->device = dmdi.data_device; amei);
} else r = -EINVAL;
device_free(dmdi.data_device); goto out;
}
if (!cd->metadata_device) {
device_free(cd, cd->device);
MOVE_REF(cd->device, tgti->data_device);
}
}
if (asprintf(&cipher_spec, "%s-%s", cipher, cipher_mode) < 0) {
cipher_spec = NULL;
r = -ENOMEM;
goto out;
} }
if (isPLAIN(cd->type)) { if (isPLAIN(cd->type)) {
cd->u.plain.hdr.hash = NULL; /* no way to get this */ cd->u.plain.hdr.hash = NULL; /* no way to get this */
cd->u.plain.hdr.offset = dmd.u.crypt.offset; cd->u.plain.hdr.offset = tgt->u.crypt.offset;
cd->u.plain.hdr.skip = dmd.u.crypt.iv_offset; cd->u.plain.hdr.skip = tgt->u.crypt.iv_offset;
cd->u.plain.hdr.sector_size = dmd.u.crypt.sector_size; cd->u.plain.hdr.sector_size = tgt->u.crypt.sector_size;
cd->u.plain.key_size = dmd.u.crypt.vk->keylength; cd->u.plain.key_size = tgt->u.crypt.vk->keylength;
cd->u.plain.cipher = strdup(cipher); cd->u.plain.cipher = strdup(cipher);
cd->u.plain.cipher_mode = strdup(cipher_mode); MOVE_REF(cd->u.plain.cipher_spec, cipher_spec);
cd->u.plain.cipher_mode = cd->u.plain.cipher_spec + strlen(cipher
) + 1;
} else if (isLOOPAES(cd->type)) { } else if (isLOOPAES(cd->type)) {
cd->u.loopaes.hdr.offset = dmd.u.crypt.offset; cd->u.loopaes.hdr.offset = tgt->u.crypt.offset;
cd->u.loopaes.cipher = strdup(cipher); cd->u.loopaes.cipher = strdup(cipher);
cd->u.loopaes.cipher_mode = strdup(cipher_mode); MOVE_REF(cd->u.loopaes.cipher_spec, cipher_spec);
cd->u.loopaes.cipher_mode = cd->u.loopaes.cipher_spec + strlen(ci
pher) + 1;
/* version 3 uses last key for IV */ /* version 3 uses last key for IV */
if (dmd.u.crypt.vk->keylength % key_nums) if (tgt->u.crypt.vk->keylength % key_nums)
key_nums++; key_nums++;
cd->u.loopaes.key_size = dmd.u.crypt.vk->keylength / key_nums; cd->u.loopaes.key_size = tgt->u.crypt.vk->keylength / key_nums;
} else if (isLUKS1(cd->type) || isLUKS2(cd->type)) { } else if (isLUKS1(cd->type) || isLUKS2(cd->type)) {
if (crypt_metadata_device(cd)) { if (crypt_metadata_device(cd)) {
r = _crypt_load_luks(cd, cd->type, 0, 0); r = _crypt_load_luks(cd, cd->type, 0, 0);
if (r < 0) { if (r < 0) {
log_dbg("LUKS device header does not match active device."); log_dbg(cd, "LUKS device header does not match ac tive device.");
crypt_set_null_type(cd); crypt_set_null_type(cd);
r = 0; r = 0;
goto out; goto out;
} }
/* check whether UUIDs match each other */ /* check whether UUIDs match each other */
r = crypt_uuid_cmp(dmd.uuid, LUKS_UUID(cd)); r = crypt_uuid_cmp(dmd.uuid, LUKS_UUID(cd));
if (r < 0) { if (r < 0) {
log_dbg("LUKS device header uuid: %s mismatches D M returned uuid %s", log_dbg(cd, "LUKS device header uuid: %s mismatch es DM returned uuid %s",
LUKS_UUID(cd), dmd.uuid); LUKS_UUID(cd), dmd.uuid);
crypt_free_type(cd); crypt_free_type(cd);
r = 0; r = 0;
goto out; goto out;
} }
} else { } else {
log_dbg("LUKS device header not available."); log_dbg(cd, "LUKS device header not available.");
crypt_set_null_type(cd); crypt_set_null_type(cd);
r = 0; r = 0;
} }
} else if (isTCRYPT(cd->type)) { } else if (isTCRYPT(cd->type)) {
r = TCRYPT_init_by_name(cd, name, &dmd, &cd->device, r = TCRYPT_init_by_name(cd, name, dmd.uuid, tgt, &cd->device,
&cd->u.tcrypt.params, &cd->u.tcrypt.hdr); &cd->u.tcrypt.params, &cd->u.tcrypt.hdr);
} }
out: out:
crypt_free_volume_key(dmd.u.crypt.vk); dm_targets_free(cd, &dmd);
device_free(dmd.data_device); dm_targets_free(cd, &dmdi);
free(CONST_CAST(void*)dmd.u.crypt.cipher);
free(CONST_CAST(void*)dmd.u.crypt.integrity);
free(CONST_CAST(void*)dmd.uuid); free(CONST_CAST(void*)dmd.uuid);
free(cipher_spec);
return r; return r;
} }
static int _init_by_name_verity(struct crypt_device *cd, const char *name) static int _init_by_name_verity(struct crypt_device *cd, const char *name)
{ {
struct crypt_params_verity params = {}; struct crypt_dm_active_device dmd;
struct crypt_dm_active_device dmd = { struct dm_target *tgt = &dmd.segment;
.target = DM_VERITY, int r;
.u.verity.vp = &params,
};
int r, verity_type = 0;
r = dm_query_device(cd, name, r = dm_query_device(cd, name,
DM_ACTIVE_DEVICE | DM_ACTIVE_DEVICE |
DM_ACTIVE_VERITY_HASH_DEVICE | DM_ACTIVE_VERITY_HASH_DEVICE |
DM_ACTIVE_VERITY_PARAMS, &dmd); DM_ACTIVE_VERITY_PARAMS, &dmd);
if (r < 0) if (r < 0)
return r;
if (!single_segment(&dmd) || tgt->type != DM_VERITY) {
log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out; goto out;
}
if (r > 0) if (r > 0)
r = 0; r = 0;
if (isVERITY(cd->type)) { if (isVERITY(cd->type)) {
cd->u.verity.uuid = NULL; // FIXME cd->u.verity.uuid = NULL; // FIXME
cd->u.verity.hdr.flags = CRYPT_VERITY_NO_HEADER; //FIXME cd->u.verity.hdr.flags = CRYPT_VERITY_NO_HEADER; //FIXME
cd->u.verity.hdr.data_size = params.data_size; cd->u.verity.hdr.data_size = tgt->u.verity.vp->data_size;
cd->u.verity.root_hash_size = dmd.u.verity.root_hash_size; cd->u.verity.root_hash_size = tgt->u.verity.root_hash_size;
cd->u.verity.root_hash = NULL; MOVE_REF(cd->u.verity.hdr.hash_name, tgt->u.verity.vp->hash_name)
cd->u.verity.hdr.hash_name = params.hash_name; ;
cd->u.verity.hdr.data_device = NULL; cd->u.verity.hdr.data_device = NULL;
cd->u.verity.hdr.hash_device = NULL; cd->u.verity.hdr.hash_device = NULL;
cd->u.verity.hdr.data_block_size = params.data_block_size; cd->u.verity.hdr.data_block_size = tgt->u.verity.vp->data_block_s
cd->u.verity.hdr.hash_block_size = params.hash_block_size; ize;
cd->u.verity.hdr.hash_area_offset = dmd.u.verity.hash_offset; cd->u.verity.hdr.hash_block_size = tgt->u.verity.vp->hash_block_s
cd->u.verity.hdr.fec_area_offset = dmd.u.verity.fec_offset; ize;
cd->u.verity.hdr.hash_type = params.hash_type; cd->u.verity.hdr.hash_area_offset = tgt->u.verity.hash_offset;
cd->u.verity.hdr.flags = params.flags; cd->u.verity.hdr.fec_area_offset = tgt->u.verity.fec_offset;
cd->u.verity.hdr.salt_size = params.salt_size; cd->u.verity.hdr.hash_type = tgt->u.verity.vp->hash_type;
cd->u.verity.hdr.salt = params.salt; cd->u.verity.hdr.flags = tgt->u.verity.vp->flags;
cd->u.verity.hdr.fec_device = params.fec_device; cd->u.verity.hdr.salt_size = tgt->u.verity.vp->salt_size;
cd->u.verity.hdr.fec_roots = params.fec_roots; MOVE_REF(cd->u.verity.hdr.salt, tgt->u.verity.vp->salt);
cd->u.verity.fec_device = dmd.u.verity.fec_device; MOVE_REF(cd->u.verity.hdr.fec_device, tgt->u.verity.vp->fec_devic
cd->metadata_device = dmd.u.verity.hash_device; e);
verity_type = 1; cd->u.verity.hdr.fec_roots = tgt->u.verity.vp->fec_roots;
MOVE_REF(cd->u.verity.fec_device, tgt->u.verity.fec_device);
MOVE_REF(cd->metadata_device, tgt->u.verity.hash_device);
} }
out: out:
if (!verity_type) { dm_targets_free(cd, &dmd);
free(CONST_CAST(void*)params.hash_name);
free(CONST_CAST(void*)params.salt);
free(CONST_CAST(void*)params.fec_device);
}
device_free(dmd.data_device);
return r; return r;
} }
static int _init_by_name_integrity(struct crypt_device *cd, const char *name) static int _init_by_name_integrity(struct crypt_device *cd, const char *name)
{ {
struct crypt_dm_active_device dmd = { struct crypt_dm_active_device dmd;
.target = DM_INTEGRITY, struct dm_target *tgt = &dmd.segment;
}; int r;
int r, integrity_type = 0;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | r = dm_query_device(cd, name, DM_ACTIVE_DEVICE |
DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEY |
DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_INTEGRITY_PARAMS, &dmd); DM_ACTIVE_INTEGRITY_PARAMS, &dmd);
if (r < 0) if (r < 0)
return r;
if (!single_segment(&dmd) || tgt->type != DM_INTEGRITY) {
log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out; goto out;
}
if (r > 0) if (r > 0)
r = 0; r = 0;
if (isINTEGRITY(cd->type)) { if (isINTEGRITY(cd->type)) {
cd->u.integrity.params.tag_size = dmd.u.integrity.tag_size; cd->u.integrity.params.tag_size = tgt->u.integrity.tag_size;
cd->u.integrity.params.sector_size = dmd.u.integrity.sector_size; cd->u.integrity.params.sector_size = tgt->u.integrity.sector_size
cd->u.integrity.params.journal_size = dmd.u.integrity.journal_siz ;
e; cd->u.integrity.params.journal_size = tgt->u.integrity.journal_si
cd->u.integrity.params.journal_watermark = dmd.u.integrity.journa ze;
l_watermark; cd->u.integrity.params.journal_watermark = tgt->u.integrity.journ
cd->u.integrity.params.journal_commit_time = dmd.u.integrity.jour al_watermark;
nal_commit_time; cd->u.integrity.params.journal_commit_time = tgt->u.integrity.jou
cd->u.integrity.params.interleave_sectors = dmd.u.integrity.inter rnal_commit_time;
leave_sectors; cd->u.integrity.params.interleave_sectors = tgt->u.integrity.inte
cd->u.integrity.params.buffer_sectors = dmd.u.integrity.buffer_se rleave_sectors;
ctors; cd->u.integrity.params.buffer_sectors = tgt->u.integrity.buffer_s
cd->u.integrity.params.integrity = dmd.u.integrity.integrity; ectors;
cd->u.integrity.params.journal_integrity = dmd.u.integrity.journa MOVE_REF(cd->u.integrity.params.integrity, tgt->u.integrity.integ
l_integrity; rity);
cd->u.integrity.params.journal_crypt = dmd.u.integrity.journal_cr MOVE_REF(cd->u.integrity.params.journal_integrity, tgt->u.integri
ypt; ty.journal_integrity);
MOVE_REF(cd->u.integrity.params.journal_crypt, tgt->u.integrity.j
if (dmd.u.integrity.vk) ournal_crypt);
cd->u.integrity.params.integrity_key_size = dmd.u.integri
ty.vk->keylength; if (tgt->u.integrity.vk)
if (dmd.u.integrity.journal_integrity_key) cd->u.integrity.params.integrity_key_size = tgt->u.integr
cd->u.integrity.params.journal_integrity_key_size = dmd.u ity.vk->keylength;
.integrity.journal_integrity_key->keylength; if (tgt->u.integrity.journal_integrity_key)
if (dmd.u.integrity.journal_crypt_key) cd->u.integrity.params.journal_integrity_key_size = tgt->
cd->u.integrity.params.integrity_key_size = dmd.u.integri u.integrity.journal_integrity_key->keylength;
ty.journal_crypt_key->keylength; if (tgt->u.integrity.journal_crypt_key)
integrity_type = 1; cd->u.integrity.params.integrity_key_size = tgt->u.integr
ity.journal_crypt_key->keylength;
MOVE_REF(cd->metadata_device, tgt->u.integrity.meta_device);
} }
out: out:
if (!integrity_type) { dm_targets_free(cd, &dmd);
free(CONST_CAST(void*)dmd.u.integrity.integrity);
free(CONST_CAST(void*)dmd.u.integrity.journal_integrity);
free(CONST_CAST(void*)dmd.u.integrity.journal_crypt);
}
crypt_free_volume_key(dmd.u.integrity.vk);
crypt_free_volume_key(dmd.u.integrity.journal_integrity_key);
crypt_free_volume_key(dmd.u.integrity.journal_crypt_key);
device_free(dmd.data_device);
return r; return r;
} }
int crypt_init_by_name_and_header(struct crypt_device **cd, int crypt_init_by_name_and_header(struct crypt_device **cd,
const char *name, const char *name,
const char *header_device) const char *header_device)
{ {
crypt_status_info ci; crypt_status_info ci;
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd;
struct dm_target *tgt = &dmd.segment;
int r; int r;
if (!cd || !name) if (!cd || !name)
return -EINVAL; return -EINVAL;
log_dbg("Allocating crypt device context by device %s.", name); log_dbg(NULL, "Allocating crypt device context by device %s.", name);
ci = crypt_status(NULL, name); ci = crypt_status(NULL, name);
if (ci == CRYPT_INVALID) if (ci == CRYPT_INVALID)
return -ENODEV; return -ENODEV;
if (ci < CRYPT_ACTIVE) { if (ci < CRYPT_ACTIVE) {
log_err(NULL, _("Device %s is not active."), name); log_err(NULL, _("Device %s is not active."), name);
return -ENODEV; return -ENODEV;
} }
r = dm_query_device(NULL, name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd); r = dm_query_device(NULL, name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd);
if (r < 0) if (r < 0)
return r;
if (!single_segment(&dmd)) {
log_dbg(NULL, "Unsupported device table detected in %s.", name);
r = -EINVAL;
goto out; goto out;
}
*cd = NULL; *cd = NULL;
if (header_device) { if (header_device) {
r = crypt_init(cd, header_device); r = crypt_init(cd, header_device);
} else { } else {
r = crypt_init(cd, device_path(dmd.data_device)); r = crypt_init(cd, device_path(tgt->data_device));
/* Underlying device disappeared but mapping still active */ /* Underlying device disappeared but mapping still active */
if (!dmd.data_device || r == -ENOTBLK) if (!tgt->data_device || r == -ENOTBLK)
log_verbose(NULL, _("Underlying device for crypt device % s disappeared."), log_verbose(NULL, _("Underlying device for crypt device % s disappeared."),
name); name);
/* Underlying device is not readable but crypt mapping exists */ /* Underlying device is not readable but crypt mapping exists */
if (r == -ENOTBLK) { if (r == -ENOTBLK)
device_free(dmd.data_device);
dmd.data_device = NULL;
r = crypt_init(cd, NULL); r = crypt_init(cd, NULL);
}
} }
if (r < 0) if (r < 0)
goto out; goto out;
if (dmd.uuid) { if (dmd.uuid) {
if (!strncmp(CRYPT_PLAIN, dmd.uuid, sizeof(CRYPT_PLAIN)-1)) if (!strncmp(CRYPT_PLAIN, dmd.uuid, sizeof(CRYPT_PLAIN)-1))
(*cd)->type = strdup(CRYPT_PLAIN); (*cd)->type = strdup(CRYPT_PLAIN);
else if (!strncmp(CRYPT_LOOPAES, dmd.uuid, sizeof(CRYPT_LOOPAES)- 1)) else if (!strncmp(CRYPT_LOOPAES, dmd.uuid, sizeof(CRYPT_LOOPAES)- 1))
(*cd)->type = strdup(CRYPT_LOOPAES); (*cd)->type = strdup(CRYPT_LOOPAES);
skipping to change at line 1303 skipping to change at line 1336
(*cd)->type = strdup(CRYPT_LUKS1); (*cd)->type = strdup(CRYPT_LUKS1);
else if (!strncmp(CRYPT_LUKS2, dmd.uuid, sizeof(CRYPT_LUKS2)-1)) else if (!strncmp(CRYPT_LUKS2, dmd.uuid, sizeof(CRYPT_LUKS2)-1))
(*cd)->type = strdup(CRYPT_LUKS2); (*cd)->type = strdup(CRYPT_LUKS2);
else if (!strncmp(CRYPT_VERITY, dmd.uuid, sizeof(CRYPT_VERITY)-1) ) else if (!strncmp(CRYPT_VERITY, dmd.uuid, sizeof(CRYPT_VERITY)-1) )
(*cd)->type = strdup(CRYPT_VERITY); (*cd)->type = strdup(CRYPT_VERITY);
else if (!strncmp(CRYPT_TCRYPT, dmd.uuid, sizeof(CRYPT_TCRYPT)-1) ) else if (!strncmp(CRYPT_TCRYPT, dmd.uuid, sizeof(CRYPT_TCRYPT)-1) )
(*cd)->type = strdup(CRYPT_TCRYPT); (*cd)->type = strdup(CRYPT_TCRYPT);
else if (!strncmp(CRYPT_INTEGRITY, dmd.uuid, sizeof(CRYPT_INTEGRI TY)-1)) else if (!strncmp(CRYPT_INTEGRITY, dmd.uuid, sizeof(CRYPT_INTEGRI TY)-1))
(*cd)->type = strdup(CRYPT_INTEGRITY); (*cd)->type = strdup(CRYPT_INTEGRITY);
else else
log_dbg("Unknown UUID set, some parameters are not set.") ; log_dbg(NULL, "Unknown UUID set, some parameters are not set.");
} else } else
log_dbg("Active device has no UUID set, some parameters are not s et."); log_dbg(NULL, "Active device has no UUID set, some parameters are not set.");
if (header_device) { if (header_device) {
r = crypt_set_data_device(*cd, device_path(dmd.data_device)); r = crypt_set_data_device(*cd, device_path(tgt->data_device));
if (r < 0) if (r < 0)
goto out; goto out;
} }
/* Try to initialise basic parameters from active device */ /* Try to initialise basic parameters from active device */
if (dmd.target == DM_CRYPT) if (tgt->type == DM_CRYPT)
r = _init_by_name_crypt(*cd, name); r = _init_by_name_crypt(*cd, name);
else if (dmd.target == DM_VERITY) else if (tgt->type == DM_VERITY)
r = _init_by_name_verity(*cd, name); r = _init_by_name_verity(*cd, name);
else if (dmd.target == DM_INTEGRITY) else if (tgt->type == DM_INTEGRITY)
r = _init_by_name_integrity(*cd, name); r = _init_by_name_integrity(*cd, name);
out: out:
if (r < 0) { if (r < 0) {
crypt_free(*cd); crypt_free(*cd);
*cd = NULL; *cd = NULL;
} else if (!(*cd)->type) { } else if (!(*cd)->type) {
/* For anonymous device (no header found) remember initialized na me */ /* For anonymous device (no header found) remember initialized na me */
(*cd)->u.none.active_name = strdup(name); (*cd)->u.none.active_name = strdup(name);
} }
device_free(dmd.data_device);
free(CONST_CAST(void*)dmd.uuid); free(CONST_CAST(void*)dmd.uuid);
dm_targets_free(NULL, &dmd);
return r; return r;
} }
int crypt_init_by_name(struct crypt_device **cd, const char *name) int crypt_init_by_name(struct crypt_device **cd, const char *name)
{ {
return crypt_init_by_name_and_header(cd, name, NULL); return crypt_init_by_name_and_header(cd, name, NULL);
} }
/* /*
* crypt_format() helpers * crypt_format() helpers
skipping to change at line 1368 skipping to change at line 1401
if (volume_key_size > 1024) { if (volume_key_size > 1024) {
log_err(cd, _("Invalid key size.")); log_err(cd, _("Invalid key size."));
return -EINVAL; return -EINVAL;
} }
if (uuid) { if (uuid) {
log_err(cd, _("UUID is not supported for this crypt type.")); log_err(cd, _("UUID is not supported for this crypt type."));
return -EINVAL; return -EINVAL;
} }
if (cd->metadata_device) {
log_err(cd, _("Detached metadata device is not supported for this
crypt type."));
return -EINVAL;
}
/* For compatibility with old params structure */ /* For compatibility with old params structure */
if (!sector_size) if (!sector_size)
sector_size = SECTOR_SIZE; sector_size = SECTOR_SIZE;
if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE || if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE ||
NOTPOW2(sector_size)) { NOTPOW2(sector_size)) {
log_err(cd, _("Unsupported encryption sector size.")); log_err(cd, _("Unsupported encryption sector size."));
return -EINVAL; return -EINVAL;
} }
skipping to change at line 1395 skipping to change at line 1433
} }
if (!(cd->type = strdup(CRYPT_PLAIN))) if (!(cd->type = strdup(CRYPT_PLAIN)))
return -ENOMEM; return -ENOMEM;
cd->u.plain.key_size = volume_key_size; cd->u.plain.key_size = volume_key_size;
cd->volume_key = crypt_alloc_volume_key(volume_key_size, NULL); cd->volume_key = crypt_alloc_volume_key(volume_key_size, NULL);
if (!cd->volume_key) if (!cd->volume_key)
return -ENOMEM; return -ENOMEM;
if (asprintf(&cd->u.plain.cipher_spec, "%s-%s", cipher, cipher_mode) < 0)
{
cd->u.plain.cipher_spec = NULL;
return -ENOMEM;
}
cd->u.plain.cipher = strdup(cipher); cd->u.plain.cipher = strdup(cipher);
cd->u.plain.cipher_mode = strdup(cipher_mode); cd->u.plain.cipher_mode = cd->u.plain.cipher_spec + strlen(cipher) + 1;
if (params && params->hash) if (params && params->hash)
cd->u.plain.hdr.hash = strdup(params->hash); cd->u.plain.hdr.hash = strdup(params->hash);
cd->u.plain.hdr.offset = params ? params->offset : 0; cd->u.plain.hdr.offset = params ? params->offset : 0;
cd->u.plain.hdr.skip = params ? params->skip : 0; cd->u.plain.hdr.skip = params ? params->skip : 0;
cd->u.plain.hdr.size = params ? params->size : 0; cd->u.plain.hdr.size = params ? params->size : 0;
cd->u.plain.hdr.sector_size = sector_size; cd->u.plain.hdr.sector_size = sector_size;
if (!cd->u.plain.cipher || !cd->u.plain.cipher_mode) if (!cd->u.plain.cipher)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
} }
static int _crypt_format_luks1(struct crypt_device *cd, static int _crypt_format_luks1(struct crypt_device *cd,
const char *cipher, const char *cipher,
const char *cipher_mode, const char *cipher_mode,
const char *uuid, const char *uuid,
const char *volume_key, const char *volume_key,
size_t volume_key_size, size_t volume_key_size,
struct crypt_params_luks1 *params) struct crypt_params_luks1 *params)
{ {
int r; int r;
unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT; unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT;
unsigned long alignment_offset = 0; unsigned long alignment_offset = 0;
uint64_t dev_size;
if (!cipher || !cipher_mode) if (!cipher || !cipher_mode)
return -EINVAL; return -EINVAL;
if (!crypt_metadata_device(cd)) { if (!crypt_metadata_device(cd)) {
log_err(cd, _("Can't format LUKS without device.")); log_err(cd, _("Can't format LUKS without device."));
return -EINVAL; return -EINVAL;
} }
if (params && cd->data_offset && params->data_alignment &&
(cd->data_offset % params->data_alignment)) {
log_err(cd, _("Requested data alignment is not compatible with da
ta offset."));
return -EINVAL;
}
if (!(cd->type = strdup(CRYPT_LUKS1))) if (!(cd->type = strdup(CRYPT_LUKS1)))
return -ENOMEM; return -ENOMEM;
if (volume_key) if (volume_key)
cd->volume_key = crypt_alloc_volume_key(volume_key_size, cd->volume_key = crypt_alloc_volume_key(volume_key_size,
volume_key); volume_key);
else else
cd->volume_key = crypt_generate_volume_key(cd, volume_key_size); cd->volume_key = crypt_generate_volume_key(cd, volume_key_size);
if (!cd->volume_key) if (!cd->volume_key)
skipping to change at line 1458 skipping to change at line 1507
} }
if (params && params->hash && strcmp(params->hash, cd->pbkdf.hash)) { if (params && params->hash && strcmp(params->hash, cd->pbkdf.hash)) {
free(CONST_CAST(void*)cd->pbkdf.hash); free(CONST_CAST(void*)cd->pbkdf.hash);
cd->pbkdf.hash = strdup(params->hash); cd->pbkdf.hash = strdup(params->hash);
if (!cd->pbkdf.hash) if (!cd->pbkdf.hash)
return -ENOMEM; return -ENOMEM;
} }
if (params && params->data_device) { if (params && params->data_device) {
cd->metadata_device = cd->device; if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL; cd->device = NULL;
if (device_alloc(&cd->device, params->data_device) < 0) if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM; return -ENOMEM;
}
if (params && cd->metadata_device) {
/* For detached header the alignment is used directly as data off
set */
if (!cd->data_offset)
cd->data_offset = params->data_alignment;
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else if (params && params->data_alignment) { } else if (params && params->data_alignment) {
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else } else
device_topology_alignment(cd->device, device_topology_alignment(cd, cd->device,
&required_alignment, &required_alignment,
&alignment_offset, DEFAULT_DISK_ALIGNMENT) ; &alignment_offset, DEFAULT_DISK_ALIGNMENT) ;
r = LUKS_check_cipher(cd, volume_key_size, cipher, cipher_mode); r = LUKS_check_cipher(cd, volume_key_size, cipher, cipher_mode);
if (r < 0) if (r < 0)
return r; return r;
r = LUKS_generate_phdr(&cd->u.luks1.hdr, cd->volume_key, cipher, cipher_m ode, r = LUKS_generate_phdr(&cd->u.luks1.hdr, cd->volume_key, cipher, cipher_m ode,
cd->pbkdf.hash, uuid, LUKS_STRIPES, cd->pbkdf.hash, uuid,
required_alignment / SECTOR_SIZE, cd->data_offset * SECTOR_SIZE,
alignment_offset / SECTOR_SIZE, alignment_offset, required_alignment, cd);
cd->metadata_device ? 1 : 0, cd);
if (r < 0) if (r < 0)
return r; return r;
r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL); r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL);
if (r < 0) if (r < 0)
return r; return r;
if (!device_size(crypt_data_device(cd), &dev_size) &&
dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE))
log_std(cd, _("WARNING: Data offset is outside of currently avail
able data device.\n"));
if (asprintf(&cd->u.luks1.cipher_spec, "%s-%s", cipher, cipher_mode) < 0)
{
cd->u.luks1.cipher_spec = NULL;
return -ENOMEM;
}
r = LUKS_wipe_header_areas(&cd->u.luks1.hdr, cd); r = LUKS_wipe_header_areas(&cd->u.luks1.hdr, cd);
if (r < 0) { if (r < 0) {
free(cd->u.luks1.cipher_spec);
log_err(cd, _("Cannot wipe header on device %s."), log_err(cd, _("Cannot wipe header on device %s."),
mdata_device_path(cd)); mdata_device_path(cd));
return r; return r;
} }
r = LUKS_write_phdr(&cd->u.luks1.hdr, cd); r = LUKS_write_phdr(&cd->u.luks1.hdr, cd);
if (r)
free(cd->u.luks1.cipher_spec);
return r; return r;
} }
static int _crypt_format_luks2(struct crypt_device *cd, static int _crypt_format_luks2(struct crypt_device *cd,
const char *cipher, const char *cipher,
const char *cipher_mode, const char *cipher_mode,
const char *uuid, const char *uuid,
const char *volume_key, const char *volume_key,
size_t volume_key_size, size_t volume_key_size,
struct crypt_params_luks2 *params) struct crypt_params_luks2 *params)
{ {
int r, integrity_key_size = 0; int r, integrity_key_size = 0;
unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT; unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT;
unsigned long alignment_offset = 0; unsigned long alignment_offset = 0;
unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE; unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE;
const char *integrity = params ? params->integrity : NULL; const char *integrity = params ? params->integrity : NULL;
uint64_t dev_size; uint64_t dev_size;
uint32_t dmc_flags;
cd->u.luks2.hdr.jobj = NULL; cd->u.luks2.hdr.jobj = NULL;
cd->u.luks2.keyslot_cipher = NULL;
if (!cipher || !cipher_mode) if (!cipher || !cipher_mode)
return -EINVAL; return -EINVAL;
if (!crypt_metadata_device(cd)) { if (!crypt_metadata_device(cd)) {
log_err(cd, _("Can't format LUKS without device.")); log_err(cd, _("Can't format LUKS without device."));
return -EINVAL; return -EINVAL;
} }
if (params && cd->data_offset && params->data_alignment &&
(cd->data_offset % params->data_alignment)) {
log_err(cd, _("Requested data alignment is not compatible with da
ta offset."));
return -EINVAL;
}
if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE || if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE ||
NOTPOW2(sector_size)) { NOTPOW2(sector_size)) {
log_err(cd, _("Unsupported encryption sector size.")); log_err(cd, _("Unsupported encryption sector size."));
return -EINVAL; return -EINVAL;
} }
if (sector_size != SECTOR_SIZE && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
!(dmc_flags & DM_SECTOR_SIZE_SUPPORTED))
log_std(cd, _("WARNING: The device activation will fail, dm-crypt
is missing "
"support for requested encryption sector size.\n"))
;
if (integrity) { if (integrity) {
if (params->integrity_params) { if (params->integrity_params) {
/* Standalone dm-integrity must not be used */ /* Standalone dm-integrity must not be used */
if (params->integrity_params->integrity || if (params->integrity_params->integrity ||
params->integrity_params->integrity_key_size) params->integrity_params->integrity_key_size)
return -EINVAL; return -EINVAL;
/* FIXME: journal encryption and MAC is here not yet supp orted */ /* FIXME: journal encryption and MAC is here not yet supp orted */
if (params->integrity_params->journal_crypt || if (params->integrity_params->journal_crypt ||
params->integrity_params->journal_integrity) params->integrity_params->journal_integrity)
skipping to change at line 1578 skipping to change at line 1659
if (params && params->pbkdf) if (params && params->pbkdf)
r = crypt_set_pbkdf_type(cd, params->pbkdf); r = crypt_set_pbkdf_type(cd, params->pbkdf);
else if (verify_pbkdf_params(cd, &cd->pbkdf)) else if (verify_pbkdf_params(cd, &cd->pbkdf))
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS2); r = init_pbkdf_type(cd, NULL, CRYPT_LUKS2);
if (r < 0) if (r < 0)
return r; return r;
if (params && params->data_device) { if (params && params->data_device) {
cd->metadata_device = cd->device; if (!cd->metadata_device)
cd->metadata_device = cd->device;
else
device_free(cd, cd->device);
cd->device = NULL; cd->device = NULL;
if (device_alloc(&cd->device, params->data_device) < 0) if (device_alloc(cd, &cd->device, params->data_device) < 0)
return -ENOMEM; return -ENOMEM;
}
if (params && cd->metadata_device) {
/* For detached header the alignment is used directly as data off
set */
if (!cd->data_offset)
cd->data_offset = params->data_alignment;
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else if (params && params->data_alignment) { } else if (params && params->data_alignment) {
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else } else
device_topology_alignment(cd->device, device_topology_alignment(cd, cd->device,
&required_alignment, &required_alignment,
&alignment_offset, DEFAULT_DISK_ALIGNMENT) ; &alignment_offset, DEFAULT_DISK_ALIGNMENT) ;
/* Save cipher and mode, compatibility only. */
cd->u.luks2.cipher = strdup(cipher);
cd->u.luks2.cipher_mode = strdup(cipher_mode);
if (!cd->u.luks2.cipher || !cd->u.luks2.cipher_mode) {
r = -ENOMEM;
goto out;
}
/* FIXME: allow this later also for normal ciphers (check AF_ALG availabi lity. */ /* FIXME: allow this later also for normal ciphers (check AF_ALG availabi lity. */
if (integrity && !integrity_key_size) { if (integrity && !integrity_key_size) {
r = crypt_cipher_check(cipher, cipher_mode, integrity, volume_key _size); r = crypt_cipher_check(cipher, cipher_mode, integrity, volume_key _size);
if (r < 0) { if (r < 0) {
log_err(cd, _("Cipher %s-%s (key size %zd bits) is not av ailable."), log_err(cd, _("Cipher %s-%s (key size %zd bits) is not av ailable."),
cipher, cipher_mode, volume_key_size * 8); cipher, cipher_mode, volume_key_size * 8);
goto out; goto out;
} }
} }
if ((!integrity || integrity_key_size) && !LUKS2_keyslot_cipher_incompati if ((!integrity || integrity_key_size) && !crypt_cipher_wrapped_key(ciphe
ble(cd)) { r, cipher_mode) &&
!INTEGRITY_tag_size(cd, NULL, cipher, cipher_mode)) {
r = LUKS_check_cipher(cd, volume_key_size - integrity_key_size, r = LUKS_check_cipher(cd, volume_key_size - integrity_key_size,
cipher, cipher_mode); cipher, cipher_mode);
if (r < 0) if (r < 0)
goto out; goto out;
} }
r = LUKS2_generate_hdr(cd, &cd->u.luks2.hdr, cd->volume_key, r = LUKS2_generate_hdr(cd, &cd->u.luks2.hdr, cd->volume_key,
cipher, cipher_mode, cipher, cipher_mode,
integrity, uuid, integrity, uuid,
sector_size, sector_size,
required_alignment, cd->data_offset * SECTOR_SIZE,
alignment_offset, alignment_offset,
cd->metadata_device ? 1 : 0); required_alignment,
cd->metadata_size, cd->keyslots_size);
if (r < 0) if (r < 0)
goto out; goto out;
if (!integrity && sector_size > SECTOR_SIZE && !device_size(crypt_data_de r = device_size(crypt_data_device(cd), &dev_size);
vice(cd), &dev_size)) { if (r < 0)
goto out;
if (dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE))
log_std(cd, _("WARNING: Data offset is outside of currently avail
able data device.\n"));
if (!integrity && sector_size > SECTOR_SIZE) {
dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE); dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE);
if (dev_size % sector_size) { if (dev_size % sector_size) {
log_err(cd, _("Device size is not aligned to requested se ctor size.")); log_err(cd, _("Device size is not aligned to requested se ctor size."));
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
} }
if (params && (params->label || params->subsystem)) { if (params && (params->label || params->subsystem)) {
r = LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, r = LUKS2_hdr_labels(cd, &cd->u.luks2.hdr,
skipping to change at line 1692 skipping to change at line 1783
else if (r == -EACCES) { else if (r == -EACCES) {
log_err(cd, _("Cannot format device %s, permission denied ."), log_err(cd, _("Cannot format device %s, permission denied ."),
mdata_device_path(cd)); mdata_device_path(cd));
r = -EINVAL; r = -EINVAL;
} else } else
log_err(cd, _("Cannot format device %s."), log_err(cd, _("Cannot format device %s."),
mdata_device_path(cd)); mdata_device_path(cd));
} }
out: out:
if (r) { if (r)
LUKS2_hdr_free(&cd->u.luks2.hdr); LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.cipher);
free(cd->u.luks2.cipher_mode);
cd->u.luks2.cipher = NULL;
cd->u.luks2.cipher_mode = NULL;
}
return r; return r;
} }
static int _crypt_format_loopaes(struct crypt_device *cd, static int _crypt_format_loopaes(struct crypt_device *cd,
const char *cipher, const char *cipher,
const char *uuid, const char *uuid,
size_t volume_key_size, size_t volume_key_size,
struct crypt_params_loopaes *params) struct crypt_params_loopaes *params)
{ {
skipping to change at line 1724 skipping to change at line 1810
if (volume_key_size > 1024) { if (volume_key_size > 1024) {
log_err(cd, _("Invalid key size.")); log_err(cd, _("Invalid key size."));
return -EINVAL; return -EINVAL;
} }
if (uuid) { if (uuid) {
log_err(cd, _("UUID is not supported for this crypt type.")); log_err(cd, _("UUID is not supported for this crypt type."));
return -EINVAL; return -EINVAL;
} }
if (cd->metadata_device) {
log_err(cd, _("Detached metadata device is not supported for this
crypt type."));
return -EINVAL;
}
if (!(cd->type = strdup(CRYPT_LOOPAES))) if (!(cd->type = strdup(CRYPT_LOOPAES)))
return -ENOMEM; return -ENOMEM;
cd->u.loopaes.key_size = volume_key_size; cd->u.loopaes.key_size = volume_key_size;
cd->u.loopaes.cipher = strdup(cipher ?: DEFAULT_LOOPAES_CIPHER); cd->u.loopaes.cipher = strdup(cipher ?: DEFAULT_LOOPAES_CIPHER);
if (params && params->hash) if (params && params->hash)
cd->u.loopaes.hdr.hash = strdup(params->hash); cd->u.loopaes.hdr.hash = strdup(params->hash);
skipping to change at line 1754 skipping to change at line 1845
int r = 0, hash_size; int r = 0, hash_size;
uint64_t data_device_size, hash_blocks_size; uint64_t data_device_size, hash_blocks_size;
struct device *fec_device = NULL; struct device *fec_device = NULL;
char *fec_device_path = NULL, *hash_name = NULL, *root_hash = NULL, *salt = NULL; char *fec_device_path = NULL, *hash_name = NULL, *root_hash = NULL, *salt = NULL;
if (!crypt_metadata_device(cd)) { if (!crypt_metadata_device(cd)) {
log_err(cd, _("Can't format VERITY without device.")); log_err(cd, _("Can't format VERITY without device."));
return -EINVAL; return -EINVAL;
} }
if (!params || !params->data_device) if (!params)
return -EINVAL;
if (!params->data_device && !cd->metadata_device)
return -EINVAL; return -EINVAL;
if (params->hash_type > VERITY_MAX_HASH_TYPE) { if (params->hash_type > VERITY_MAX_HASH_TYPE) {
log_err(cd, _("Unsupported VERITY hash type %d."), params->hash_t ype); log_err(cd, _("Unsupported VERITY hash type %d."), params->hash_t ype);
return -EINVAL; return -EINVAL;
} }
if (VERITY_BLOCK_SIZE_OK(params->data_block_size) || if (VERITY_BLOCK_SIZE_OK(params->data_block_size) ||
VERITY_BLOCK_SIZE_OK(params->hash_block_size)) { VERITY_BLOCK_SIZE_OK(params->hash_block_size)) {
log_err(cd, _("Unsupported VERITY block size.")); log_err(cd, _("Unsupported VERITY block size."));
skipping to change at line 1781 skipping to change at line 1875
} }
if (MISALIGNED_512(params->fec_area_offset)) { if (MISALIGNED_512(params->fec_area_offset)) {
log_err(cd, _("Unsupported VERITY FEC offset.")); log_err(cd, _("Unsupported VERITY FEC offset."));
return -EINVAL; return -EINVAL;
} }
if (!(cd->type = strdup(CRYPT_VERITY))) if (!(cd->type = strdup(CRYPT_VERITY)))
return -ENOMEM; return -ENOMEM;
r = crypt_set_data_device(cd, params->data_device); if (params->data_device) {
if (r) r = crypt_set_data_device(cd, params->data_device);
return r; if (r)
return r;
}
if (!params->data_size) { if (!params->data_size) {
r = device_size(cd->device, &data_device_size); r = device_size(cd->device, &data_device_size);
if (r < 0) if (r < 0)
return r; return r;
cd->u.verity.hdr.data_size = data_device_size / params->data_bloc k_size; cd->u.verity.hdr.data_size = data_device_size / params->data_bloc k_size;
} else } else
cd->u.verity.hdr.data_size = params->data_size; cd->u.verity.hdr.data_size = params->data_size;
if (device_is_identical(crypt_metadata_device(cd), crypt_data_device(cd)) && if (device_is_identical(crypt_metadata_device(cd), crypt_data_device(cd)) &&
skipping to change at line 1811 skipping to change at line 1908
log_err(cd, _("Hash algorithm %s not supported."), log_err(cd, _("Hash algorithm %s not supported."),
params->hash_name); params->hash_name);
return -EINVAL; return -EINVAL;
} }
cd->u.verity.root_hash_size = hash_size; cd->u.verity.root_hash_size = hash_size;
if (params->fec_device) { if (params->fec_device) {
fec_device_path = strdup(params->fec_device); fec_device_path = strdup(params->fec_device);
if (!fec_device_path) if (!fec_device_path)
return -ENOMEM; return -ENOMEM;
r = device_alloc(&fec_device, params->fec_device); r = device_alloc(cd, &fec_device, params->fec_device);
if (r < 0) { if (r < 0) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto err;
} }
hash_blocks_size = VERITY_hash_blocks(cd, params) * params->hash_ block_size; hash_blocks_size = VERITY_hash_blocks(cd, params) * params->hash_ block_size;
if (device_is_identical(crypt_metadata_device(cd), fec_device) && if (device_is_identical(crypt_metadata_device(cd), fec_device) &&
(params->hash_area_offset + hash_blocks_size) > params->fec_a rea_offset) { (params->hash_area_offset + hash_blocks_size) > params->fec_a rea_offset) {
log_err(cd, _("Hash area overlaps with FEC area.")); log_err(cd, _("Hash area overlaps with FEC area."));
r = -EINVAL; r = -EINVAL;
skipping to change at line 1889 skipping to change at line 1986
r = VERITY_UUID_generate(cd, &cd->u.verity.uuid); r = VERITY_UUID_generate(cd, &cd->u.verity.uuid);
if (!r) if (!r)
r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset , r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset ,
cd->u.verity.uuid, cd->u.verity.uuid,
&cd->u.verity.hdr); &cd->u.verity.hdr);
} }
err: err:
if (r) { if (r) {
device_free(fec_device); device_free(cd, fec_device);
free(root_hash); free(root_hash);
free(hash_name); free(hash_name);
free(fec_device_path); free(fec_device_path);
free(salt); free(salt);
} }
return r; return r;
} }
static int _crypt_format_integrity(struct crypt_device *cd, static int _crypt_format_integrity(struct crypt_device *cd,
skipping to change at line 2004 skipping to change at line 2101
const char *volume_key, const char *volume_key,
size_t volume_key_size, size_t volume_key_size,
void *params) void *params)
{ {
int r; int r;
if (!cd || !type) if (!cd || !type)
return -EINVAL; return -EINVAL;
if (cd->type) { if (cd->type) {
log_dbg("Context already formatted as %s.", cd->type); log_dbg(cd, "Context already formatted as %s.", cd->type);
return -EINVAL; return -EINVAL;
} }
log_dbg("Formatting device %s as type %s.", mdata_device_path(cd) ?: "(no ne)", type); log_dbg(cd, "Formatting device %s as type %s.", mdata_device_path(cd) ?: "(none)", type);
crypt_reset_null_type(cd); crypt_reset_null_type(cd);
r = init_crypto(cd); r = init_crypto(cd);
if (r < 0) if (r < 0)
return r; return r;
if (isPLAIN(type)) if (isPLAIN(type))
r = _crypt_format_plain(cd, cipher, cipher_mode, r = _crypt_format_plain(cd, cipher, cipher_mode,
uuid, volume_key_size, params); uuid, volume_key_size, params);
skipping to change at line 2036 skipping to change at line 2133
r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, para ms); r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, para ms);
else if (isVERITY(type)) else if (isVERITY(type))
r = _crypt_format_verity(cd, uuid, params); r = _crypt_format_verity(cd, uuid, params);
else if (isINTEGRITY(type)) else if (isINTEGRITY(type))
r = _crypt_format_integrity(cd, uuid, params); r = _crypt_format_integrity(cd, uuid, params);
else { else {
log_err(cd, _("Unknown crypt device type %s requested."), type); log_err(cd, _("Unknown crypt device type %s requested."), type);
r = -EINVAL; r = -EINVAL;
} }
if (r < 0) { if (r < 0) {
crypt_set_null_type(cd); crypt_set_null_type(cd);
crypt_free_volume_key(cd->volume_key); crypt_free_volume_key(cd->volume_key);
cd->volume_key = NULL; cd->volume_key = NULL;
}
return r;
}
int crypt_repair(struct crypt_device *cd,
const char *requested_type,
void *params __attribute__((unused)))
{
int r;
if (!cd)
return -EINVAL;
log_dbg(cd, "Trying to repair %s crypt type from device %s.",
requested_type ?: "any", mdata_device_path(cd) ?: "(none)");
if (!crypt_metadata_device(cd))
return -EINVAL;
if (requested_type && !isLUKS(requested_type))
return -EINVAL;
/* Load with repair */
r = _crypt_load_luks(cd, requested_type, 1, 1);
if (r < 0)
return r;
/* cd->type and header must be set in context */
r = crypt_check_data_device_size(cd);
if (r < 0)
crypt_set_null_type(cd);
return r;
}
/* compare volume keys */
static int _compare_volume_keys(struct volume_key *svk, unsigned skeyring_only,
struct volume_key *tvk, unsigned tkeyring_only)
{
if (!svk && !tvk)
return 0;
else if (!svk || !tvk)
return 1;
if (svk->keylength != tvk->keylength)
return 1;
if (!skeyring_only && !tkeyring_only)
return memcmp(svk->key, tvk->key, svk->keylength);
return 0;
}
/* compare two strings (allows NULL) */
static int _strcmp_null(const char *a, const char *b)
{
if (!a && !b)
return 0;
else if (!a || !b)
return 1;
return strcmp(a, b);
}
static int _compare_device_types(struct crypt_device *cd,
const struct crypt_dm_active_device *src,
const struct crypt_dm_active_device *tgt)
{
if (!tgt->uuid) {
log_dbg(cd, "Missing device uuid in target device.");
return -EINVAL;
}
if (isLUKS2(cd->type) && !src->uuid) {
if (strncmp("INTEGRITY-", tgt->uuid, strlen("INTEGRITY-"))) {
log_dbg(cd, "Unexpected uuid prefix %s in target integrit
y device.", tgt->uuid);
return -EINVAL;
}
} else if (isLUKS(cd->type)) {
if (!src->uuid || strncmp(cd->type, tgt->uuid, strlen(cd->type))
||
crypt_uuid_cmp(tgt->uuid, src->uuid)) {
log_dbg(cd, "LUKS UUID mismatch.");
return -EINVAL;
}
} else if (isPLAIN(cd->type) || isLOOPAES(cd->type)) {
if (strncmp(cd->type, tgt->uuid, strlen(cd->type))) {
log_dbg(cd, "Unexpected uuid prefix %s in target device."
, tgt->uuid);
return -EINVAL;
}
} else {
log_dbg(cd, "Unsupported device type %s for reload.", cd->type ?:
"<empty>");
return -ENOTSUP;
}
return 0;
}
static int _compare_crypt_devices(struct crypt_device *cd,
const struct dm_target *src,
const struct dm_target *tgt)
{
/* for crypt devices keys are mandatory */
if (!src->u.crypt.vk || !tgt->u.crypt.vk)
return -EINVAL;
if (_compare_volume_keys(src->u.crypt.vk, 0, tgt->u.crypt.vk, tgt->u.cryp
t.vk->key_description != NULL)) {
log_dbg(cd, "Keys in context and target device do not match.");
return -EINVAL;
}
/* CIPHER checks */
if (!src->u.crypt.cipher || !tgt->u.crypt.cipher)
return -EINVAL;
if (strcmp(src->u.crypt.cipher, tgt->u.crypt.cipher)) {
log_dbg(cd, "Cipher specs do not match.");
return -EINVAL;
}
if (_strcmp_null(src->u.crypt.integrity, tgt->u.crypt.integrity)) {
log_dbg(cd, "Integrity parameters do not match.");
return -EINVAL;
}
if (src->u.crypt.offset != tgt->u.crypt.offset ||
src->u.crypt.sector_size != tgt->u.crypt.sector_size ||
src->u.crypt.iv_offset != tgt->u.crypt.iv_offset ||
src->u.crypt.tag_size != tgt->u.crypt.tag_size) {
log_dbg(cd, "Integer parameters do not match.");
return -EINVAL;
}
if (!device_is_identical(src->data_device, tgt->data_device)) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
}
return 0;
}
static int _compare_integrity_devices(struct crypt_device *cd,
const struct dm_target *src,
const struct dm_target *tgt)
{
/*
* some parameters may be implicit (and set in dm-integrity ctor)
*
* journal_size
* journal_watermark
* journal_commit_time
* buffer_sectors
* interleave_sectors
*/
/* check remaining integer values that makes sense */
if (src->u.integrity.tag_size != tgt->u.integrity.tag_size ||
src->u.integrity.offset != tgt->u.integrity.offset ||
src->u.integrity.sector_size != tgt->u.integrity.sector_size) {
log_dbg(cd, "Integer parameters do not match.");
return -EINVAL;
}
if (_strcmp_null(src->u.integrity.integrity, tgt->u.integrity.int
egrity) ||
_strcmp_null(src->u.integrity.journal_integrity, tgt->u.integrity.jou
rnal_integrity) ||
_strcmp_null(src->u.integrity.journal_crypt, tgt->u.integrity.jou
rnal_crypt)) {
log_dbg(cd, "Journal parameters do not match.");
return -EINVAL;
}
/* unfortunately dm-integrity doesn't support keyring */
if (_compare_volume_keys(src->u.integrity.vk, 0, tgt->u.integrity.vk, 0)
||
_compare_volume_keys(src->u.integrity.journal_integrity_key, 0, tgt->
u.integrity.journal_integrity_key, 0) ||
_compare_volume_keys(src->u.integrity.journal_crypt_key, 0, tgt->u.in
tegrity.journal_crypt_key, 0)) {
log_dbg(cd, "Journal keys do not match.");
return -EINVAL;
}
/* unsupported underneath dm-crypt with auth. encryption */
if (src->u.integrity.meta_device || tgt->u.integrity.meta_device)
return -ENOTSUP;
if (src->size != tgt->size) {
log_dbg(cd, "Device size parameters do not match.");
return -EINVAL;
}
if (!device_is_identical(src->data_device, tgt->data_device)) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
}
return 0;
}
static int _compare_dm_devices(struct crypt_device *cd,
const struct crypt_dm_active_device *src,
const struct crypt_dm_active_device *tgt)
{
int r;
const struct dm_target *s, *t;
if (!src || !tgt)
return -EINVAL;
r = _compare_device_types(cd, src, tgt);
if (r)
return r;
s = &src->segment;
t = &tgt->segment;
while (s || t) {
if (!s || !t) {
log_dbg(cd, "segments count mismatch.");
return -EINVAL;
}
if (s->type != t->type) {
log_dbg(cd, "segment type mismatch.");
r = -EINVAL;
break;
}
switch (s->type) {
case DM_CRYPT:
r = _compare_crypt_devices(cd, s, t);
break;
case DM_INTEGRITY:
r = _compare_integrity_devices(cd, s, t);
break;
default:
r = -ENOTSUP;
}
if (r)
break;
s = s->next;
t = t->next;
}
return r;
}
static int _reload_device(struct crypt_device *cd, const char *name,
struct crypt_dm_active_device *sdmd)
{
int r;
struct crypt_dm_active_device tdmd;
struct dm_target *src, *tgt = &tdmd.segment;
if (!cd || !cd->type || !name || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
return -EINVAL;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || tgt->u.crypt.tag_s
ize) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name);
goto out;
}
r = _compare_dm_devices(cd, sdmd, &tdmd);
if (r) {
log_err(cd, _("Mismatching parameters on device %s."), name);
goto out;
}
src = &sdmd->segment;
/* Changing read only flag for active device makes no sense */
if (tdmd.flags & CRYPT_ACTIVATE_READONLY)
sdmd->flags |= CRYPT_ACTIVATE_READONLY;
else
sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;
if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.cryp
t.vk->key_description);
if (r)
goto out;
} else {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keyleng
th, src->u.crypt.vk->key);
if (!tgt->u.crypt.vk) {
r = -ENOMEM;
goto out;
}
}
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
if (r)
goto out;
tdmd.flags = sdmd->flags;
tgt->size = tdmd.size = sdmd->size;
r = dm_reload_device(cd, name, &tdmd, 1);
out:
dm_targets_free(cd, &tdmd);
free(CONST_CAST(void*)tdmd.uuid);
return r;
}
static int _reload_device_with_integrity(struct crypt_device *cd,
const char *name,
const char *iname,
const char *ipath,
struct crypt_dm_active_device *sdmd,
struct crypt_dm_active_device *sdmdi)
{
int r;
struct crypt_dm_active_device tdmd, tdmdi = {};
struct dm_target *src, *srci, *tgt = &tdmd.segment, *tgti = &tdmdi.segmen
t;
struct device *data_device = NULL;
if (!cd || !cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE
_REFRESH))
return -EINVAL;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd);
if (r < 0) {
log_err(cd, _("Device %s is not active."), name);
return -EINVAL;
}
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || !tgt->u.crypt.tag_
size) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name);
goto out;
}
r = dm_query_device(cd, iname, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &tdmdi)
;
if (r < 0) {
log_err(cd, _("Device %s is not active."), iname);
r = -EINVAL;
goto out;
}
if (!single_segment(&tdmdi) || tgti->type != DM_INTEGRITY) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), iname);
goto out;
}
r = _compare_dm_devices(cd, sdmdi, &tdmdi);
if (r) {
log_err(cd, _("Mismatching parameters on device %s."), iname);
goto out;
}
src = &sdmd->segment;
srci = &sdmdi->segment;
r = device_alloc(cd, &data_device, ipath);
if (r < 0)
goto out;
r = device_block_adjust(cd, srci->data_device, DEV_OK,
srci->u.integrity.offset, &sdmdi->size, NULL);
if (r)
goto out;
src->data_device = data_device;
r = _compare_dm_devices(cd, sdmd, &tdmd);
if (r) {
log_err(cd, "Crypt devices mismatch.");
goto out;
}
/* Changing read only flag for active device makes no sense */
if (tdmd.flags & CRYPT_ACTIVATE_READONLY)
sdmd->flags |= CRYPT_ACTIVATE_READONLY;
else
sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;
if (tdmdi.flags & CRYPT_ACTIVATE_READONLY)
sdmdi->flags |= CRYPT_ACTIVATE_READONLY;
else
sdmdi->flags &= ~CRYPT_ACTIVATE_READONLY;
if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.cryp
t.vk->key_description);
if (r)
goto out;
} else {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keyleng
th, src->u.crypt.vk->key);
if (!tgt->u.crypt.vk) {
r = -ENOMEM;
goto out;
}
}
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
if (r)
goto out;
tdmd.flags = sdmd->flags;
tdmd.size = sdmd->size;
if ((r = dm_reload_device(cd, iname, sdmdi, 0))) {
log_dbg(cd, "Failed to reload device %s.", iname);
goto out;
} }
return r; if ((r = dm_reload_device(cd, name, &tdmd, 0))) {
} log_dbg(cd, "Failed to reload device %s.", name);
goto err_clear;
}
int crypt_repair(struct crypt_device *cd, if ((r = dm_suspend_device(cd, name))) {
const char *requested_type, log_dbg(cd, "Failed to suspend device %s.", name);
void *params __attribute__((unused))) goto err_clear;
{ }
int r;
if (!cd) if ((r = dm_suspend_device(cd, iname))) {
return -EINVAL; log_err(cd, "Failed to suspend device %s.", iname);
goto err_clear;
}
log_dbg("Trying to repair %s crypt type from device %s.", if ((r = dm_resume_device(cd, iname, sdmdi->flags))) {
requested_type ?: "any", mdata_device_path(cd) ?: "(none)"); log_err(cd, "Failed to resume device %s.", iname);
goto err_clear;
}
if (!crypt_metadata_device(cd)) r = dm_resume_device(cd, name, tdmd.flags);
return -EINVAL; if (!r)
goto out;
if (requested_type && !isLUKS(requested_type)) /*
return -EINVAL; * This is worst case scenario. We have active underlying dm-integrity de
vice with
* new table but dm-crypt resume failed for some reason. Tear everything
down and
* burn it for good.
*/
/* Load with repair */ log_err(cd, "Fatal error while reloading device %s (on top of device %s).
r = _crypt_load_luks(cd, requested_type, 1, 1); ", name, iname);
if (r < 0)
return r;
/* cd->type and header must be set in context */ if (dm_error_device(cd, name))
r = crypt_check_data_device_size(cd); log_err(cd, "Failed to switch device %s to dm-error.", name);
if (r < 0) if (dm_error_device(cd, iname))
crypt_set_null_type(cd); log_err(cd, "Failed to switch device %s to dm-error.", iname);
goto out;
err_clear:
dm_clear_device(cd, name);
dm_clear_device(cd, iname);
if (dm_status_suspended(cd, name) > 0)
dm_resume_device(cd, name, 0);
if (dm_status_suspended(cd, iname) > 0)
dm_resume_device(cd, iname, 0);
out:
dm_targets_free(cd, &tdmd);
dm_targets_free(cd, &tdmdi);
free(CONST_CAST(void*)tdmdi.uuid);
free(CONST_CAST(void*)tdmd.uuid);
device_free(cd, data_device);
return r; return r;
} }
int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{ {
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmdq, dmd = {};
struct dm_target *tgt = &dmdq.segment;
int r; int r;
/* /*
* FIXME: check context uuid matches the dm-crypt device uuid. * FIXME: Also with LUKS2 we must not allow resize when there's
* Currently it's possible to resize device (name)
* unrelated to device loaded in context.
*
* Also with LUKS2 we must not allow resize when there's
* explicit size stored in metadata (length != "dynamic") * explicit size stored in metadata (length != "dynamic")
*/ */
/* Device context type must be initialised */ /* Device context type must be initialised */
if (!cd || !cd->type || !name) if (!cd || !cd->type || !name)
return -EINVAL; return -EINVAL;
log_dbg("Resizing device %s to %" PRIu64 " sectors.", name, new_size); log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size) ;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER | r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_K
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE | EY, &dmdq);
DM_ACTIVE_CRYPT_KEY, &dmd);
if (r < 0) { if (r < 0) {
log_err(NULL, _("Device %s is not active."), name); log_err(cd, _("Device %s is not active."), name);
return -EINVAL; return -EINVAL;
} }
if (!single_segment(&dmdq) || tgt->type != DM_CRYPT) {
if (!dmd.uuid || dmd.target != DM_CRYPT) { log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
if ((dmd.flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_key_in_keyring(cd) ) { if ((dmdq.flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_key_in_keyring(cd )) {
r = -EPERM; r = -EPERM;
goto out; goto out;
} }
if (crypt_key_in_keyring(cd)) { if (crypt_key_in_keyring(cd)) {
if (!isLUKS2(cd->type)) { if (!isLUKS2(cd->type)) {
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
r = LUKS2_key_description_by_segment(cd, &cd->u.luks2.hdr, r = LUKS2_key_description_by_segment(cd, &cd->u.luks2.hdr,
dmd.u.crypt.vk, CRYPT_DEFAULT_SEGMENT); tgt->u.crypt.vk, CRYPT_DEFAULT_SEGMENT);
if (r) if (r)
goto out; goto out;
dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY; dmdq.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
} }
if (crypt_loop_device(crypt_get_device_name(cd))) { if (crypt_loop_device(crypt_get_device_name(cd))) {
log_dbg("Trying to resize underlying loop device %s.", log_dbg(cd, "Trying to resize underlying loop device %s.",
crypt_get_device_name(cd)); crypt_get_device_name(cd));
/* Here we always use default size not new_size */ /* Here we always use default size not new_size */
if (crypt_loop_resize(crypt_get_device_name(cd))) if (crypt_loop_resize(crypt_get_device_name(cd)))
log_err(NULL, _("Cannot resize loop device.")); log_err(cd, _("Cannot resize loop device."));
} }
r = device_block_adjust(cd, dmd.data_device, DEV_OK, r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
dmd.u.crypt.offset, &new_size, &dmd.flags); crypt_get_data_offset(cd), &new_size, &dmdq.flags
);
if (r) if (r)
goto out; goto out;
if (MISALIGNED(new_size, dmd.u.crypt.sector_size >> SECTOR_SHIFT)) { if (MISALIGNED(new_size, tgt->u.crypt.sector_size >> SECTOR_SHIFT)) {
log_err(cd, _("Device %s size is not aligned to requested sector size (%u bytes)."), log_err(cd, _("Device %s size is not aligned to requested sector size (%u bytes)."),
crypt_get_device_name(cd), (unsigned)dmd.u.crypt.sector_s ize); crypt_get_device_name(cd), (unsigned)tgt->u.crypt.sector_ size);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
if (new_size == dmd.size) { dmd.uuid = crypt_get_uuid(cd);
log_dbg("Device has already requested size %" PRIu64 dmd.size = new_size;
" sectors.", dmd.size); dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH;
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd)
,
crypt_get_sector_size(cd));
if (r < 0)
goto out;
if (new_size == dmdq.size) {
log_dbg(cd, "Device has already requested size %" PRIu64
" sectors.", dmdq.size);
r = 0; r = 0;
} else { } else {
dmd.size = new_size;
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
r = -ENOTSUP; r = -ENOTSUP;
else if (isLUKS2(cd->type)) else if (isLUKS2(cd->type))
r = LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, 0); r = LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, 0);
if (!r) if (!r)
r = dm_create_device(cd, name, cd->type, &dmd, 1); r = _reload_device(cd, name, &dmd);
} }
out: out:
if (dmd.target == DM_CRYPT) { dm_targets_free(cd, &dmd);
crypt_free_volume_key(dmd.u.crypt.vk); dm_targets_free(cd, &dmdq);
free(CONST_CAST(void*)dmd.u.crypt.cipher);
free(CONST_CAST(void*)dmd.u.crypt.integrity);
}
device_free(dmd.data_device);
free(CONST_CAST(void*)dmd.uuid);
return r; return r;
} }
int crypt_set_uuid(struct crypt_device *cd, const char *uuid) int crypt_set_uuid(struct crypt_device *cd, const char *uuid)
{ {
const char *active_uuid; const char *active_uuid;
int r; int r;
log_dbg("%s device uuid.", uuid ? "Setting new" : "Refreshing"); log_dbg(cd, "%s device uuid.", uuid ? "Setting new" : "Refreshing");
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
active_uuid = crypt_get_uuid(cd); active_uuid = crypt_get_uuid(cd);
if (uuid && active_uuid && !strncmp(uuid, active_uuid, UUID_STRING_L)) { if (uuid && active_uuid && !strncmp(uuid, active_uuid, UUID_STRING_L)) {
log_dbg("UUID is the same as requested (%s) for device %s.", log_dbg(cd, "UUID is the same as requested (%s) for device %s.",
uuid, mdata_device_path(cd)); uuid, mdata_device_path(cd));
return 0; return 0;
} }
if (uuid) if (uuid)
log_dbg("Requested new UUID change to %s for %s.", uuid, mdata_de vice_path(cd)); log_dbg(cd, "Requested new UUID change to %s for %s.", uuid, mdat a_device_path(cd));
else else
log_dbg("Requested new UUID refresh for %s.", mdata_device_path(c d)); log_dbg(cd, "Requested new UUID refresh for %s.", mdata_device_pa th(cd));
if (!crypt_confirm(cd, _("Do you really want to change UUID of device?")) ) if (!crypt_confirm(cd, _("Do you really want to change UUID of device?")) )
return -EPERM; return -EPERM;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return LUKS_hdr_uuid_set(&cd->u.luks1.hdr, uuid, cd); return LUKS_hdr_uuid_set(&cd->u.luks1.hdr, uuid, cd);
else else
return LUKS2_hdr_uuid(cd, &cd->u.luks2.hdr, uuid); return LUKS2_hdr_uuid(cd, &cd->u.luks2.hdr, uuid);
} }
int crypt_set_label(struct crypt_device *cd, const char *label, const char *subs ystem) int crypt_set_label(struct crypt_device *cd, const char *label, const char *subs ystem)
{ {
int r; int r;
log_dbg("Setting new labels."); log_dbg(cd, "Setting new labels.");
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, label, subsystem, 1); return LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, label, subsystem, 1);
} }
int crypt_header_backup(struct crypt_device *cd, int crypt_header_backup(struct crypt_device *cd,
const char *requested_type, const char *requested_type,
const char *backup_file) const char *backup_file)
skipping to change at line 2233 skipping to change at line 2762
return -EINVAL; return -EINVAL;
if (!backup_file) if (!backup_file)
return -EINVAL; return -EINVAL;
/* Load with repair */ /* Load with repair */
r = _crypt_load_luks(cd, requested_type, 1, 0); r = _crypt_load_luks(cd, requested_type, 1, 0);
if (r < 0) if (r < 0)
return r; return r;
log_dbg("Requested header backup of device %s (%s) to " log_dbg(cd, "Requested header backup of device %s (%s) to "
"file %s.", mdata_device_path(cd), requested_type ?: "any type", backup_file); "file %s.", mdata_device_path(cd), requested_type ?: "any type", backup_file);
if (isLUKS1(cd->type) && (!requested_type || isLUKS1(requested_type))) if (isLUKS1(cd->type) && (!requested_type || isLUKS1(requested_type)))
r = LUKS_hdr_backup(backup_file, cd); r = LUKS_hdr_backup(backup_file, cd);
else if (isLUKS2(cd->type) && (!requested_type || isLUKS2(requested_type) )) else if (isLUKS2(cd->type) && (!requested_type || isLUKS2(requested_type) ))
r = LUKS2_hdr_backup(cd, &cd->u.luks2.hdr, backup_file); r = LUKS2_hdr_backup(cd, &cd->u.luks2.hdr, backup_file);
else else
r = -EINVAL; r = -EINVAL;
return r; return r;
skipping to change at line 2264 skipping to change at line 2793
if (requested_type && !isLUKS(requested_type)) if (requested_type && !isLUKS(requested_type))
return -EINVAL; return -EINVAL;
if (!cd || (cd->type && !isLUKS(cd->type)) || !backup_file) if (!cd || (cd->type && !isLUKS(cd->type)) || !backup_file)
return -EINVAL; return -EINVAL;
r = init_crypto(cd); r = init_crypto(cd);
if (r < 0) if (r < 0)
return r; return r;
log_dbg("Requested header restore to device %s (%s) from " log_dbg(cd, "Requested header restore to device %s (%s) from "
"file %s.", mdata_device_path(cd), requested_type ?: "any type", backup_file); "file %s.", mdata_device_path(cd), requested_type ?: "any type", backup_file);
version = LUKS2_hdr_version_unlocked(cd, backup_file); version = LUKS2_hdr_version_unlocked(cd, backup_file);
if (!version || if (!version ||
(requested_type && version == 1 && !isLUKS1(requested_type)) || (requested_type && version == 1 && !isLUKS1(requested_type)) ||
(requested_type && version == 2 && !isLUKS2(requested_type))) { (requested_type && version == 2 && !isLUKS2(requested_type))) {
log_err(cd, _("Header backup file does not contain compatible LUK S header.")); log_err(cd, _("Header backup file does not contain compatible LUK S header."));
return -EINVAL; return -EINVAL;
} }
skipping to change at line 2305 skipping to change at line 2834
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2 , 1, 1); r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2 , 1, 1);
return r; return r;
} }
void crypt_free(struct crypt_device *cd) void crypt_free(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return; return;
log_dbg("Releasing crypt device %s context.", mdata_device_path(cd)); log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd));
dm_backend_exit(); dm_backend_exit(cd);
crypt_free_volume_key(cd->volume_key); crypt_free_volume_key(cd->volume_key);
device_free(cd->device); device_free(cd, cd->device);
device_free(cd->metadata_device); device_free(cd, cd->metadata_device);
free(CONST_CAST(void*)cd->pbkdf.type); free(CONST_CAST(void*)cd->pbkdf.type);
free(CONST_CAST(void*)cd->pbkdf.hash); free(CONST_CAST(void*)cd->pbkdf.hash);
crypt_free_type(cd); crypt_free_type(cd);
/* Some structures can contain keys (TCRYPT), wipe it */ /* Some structures can contain keys (TCRYPT), wipe it */
crypt_memzero(cd, sizeof(*cd)); crypt_memzero(cd, sizeof(*cd));
free(cd); free(cd);
} }
static char *crypt_get_device_key_description(const char *name) static char *crypt_get_device_key_description(struct crypt_device *cd, const cha r *name)
{ {
char *tmp = NULL; char *desc = NULL;
struct crypt_dm_active_device dmd; struct crypt_dm_active_device dmd;
struct dm_target *tgt = &dmd.segment;
if (dm_query_device(NULL, name, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEY SIZE, &dmd) < 0) if (dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSI ZE, &dmd) < 0)
return NULL; return NULL;
if (dmd.target == DM_CRYPT) { if (single_segment(&dmd) && tgt->type == DM_CRYPT &&
if ((dmd.flags & CRYPT_ACTIVATE_KEYRING_KEY) && dmd.u.crypt.vk->k (dmd.flags & CRYPT_ACTIVATE_KEYRING_KEY) && tgt->u.crypt.vk->key_desc
ey_description) ription)
tmp = strdup(dmd.u.crypt.vk->key_description); desc = strdup(tgt->u.crypt.vk->key_description);
crypt_free_volume_key(dmd.u.crypt.vk);
} else if (dmd.target == DM_INTEGRITY) {
crypt_free_volume_key(dmd.u.integrity.vk);
}
return tmp; dm_targets_free(cd, &dmd);
return desc;
} }
int crypt_suspend(struct crypt_device *cd, int crypt_suspend(struct crypt_device *cd,
const char *name) const char *name)
{ {
char *key_desc; char *key_desc;
crypt_status_info ci; crypt_status_info ci;
int r; int r;
/* FIXME: check context uuid matches the dm-crypt device uuid (onlyLUKS b ranching) */ /* FIXME: check context uuid matches the dm-crypt device uuid (onlyLUKS b ranching) */
if (!cd || !name) if (!cd || !name)
return -EINVAL; return -EINVAL;
log_dbg("Suspending volume %s.", name); log_dbg(cd, "Suspending volume %s.", name);
if (cd->type) if (cd->type)
r = onlyLUKS(cd); r = onlyLUKS(cd);
else { else {
r = crypt_uuid_type_cmp(cd, CRYPT_LUKS1); r = crypt_uuid_type_cmp(cd, CRYPT_LUKS1);
if (r < 0) if (r < 0)
r = crypt_uuid_type_cmp(cd, CRYPT_LUKS2); r = crypt_uuid_type_cmp(cd, CRYPT_LUKS2);
if (r < 0) if (r < 0)
log_err(cd, _("This operation is supported only for LUKS device.")); log_err(cd, _("This operation is supported only for LUKS device."));
} }
if (r < 0) if (r < 0)
return r; return r;
ci = crypt_status(NULL, name); ci = crypt_status(NULL, name);
if (ci < CRYPT_ACTIVE) { if (ci < CRYPT_ACTIVE) {
log_err(cd, _("Volume %s is not active."), name); log_err(cd, _("Volume %s is not active."), name);
return -EINVAL; return -EINVAL;
} }
dm_backend_init(); dm_backend_init(cd);
r = dm_status_suspended(cd, name); r = dm_status_suspended(cd, name);
if (r < 0) if (r < 0)
goto out; goto out;
if (r) { if (r) {
log_err(cd, _("Volume %s is already suspended."), name); log_err(cd, _("Volume %s is already suspended."), name);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
key_desc = crypt_get_device_key_description(name); key_desc = crypt_get_device_key_description(cd, name);
/* we can't simply wipe wrapped keys */ /* we can't simply wipe wrapped keys */
if (crypt_cipher_wrapped_key(crypt_get_cipher(cd), crypt_get_cipher_mode( cd))) if (crypt_cipher_wrapped_key(crypt_get_cipher(cd), crypt_get_cipher_mode( cd)))
r = dm_suspend_device(cd, name); r = dm_suspend_device(cd, name);
else else
r = dm_suspend_and_wipe_key(cd, name); r = dm_suspend_and_wipe_key(cd, name);
if (r == -ENOTSUP) if (r == -ENOTSUP)
log_err(cd, _("Suspend is not supported for device %s."), name); log_err(cd, _("Suspend is not supported for device %s."), name);
else if (r) else if (r)
log_err(cd, _("Error during suspending device %s."), name); log_err(cd, _("Error during suspending device %s."), name);
else else
crypt_drop_keyring_key(cd, key_desc); crypt_drop_keyring_key(cd, key_desc);
free(key_desc); free(key_desc);
out: out:
dm_backend_exit(); dm_backend_exit(cd);
return r; return r;
} }
int crypt_resume_by_passphrase(struct crypt_device *cd, int crypt_resume_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
int keyslot, int keyslot,
const char *passphrase, const char *passphrase,
size_t passphrase_size) size_t passphrase_size)
{ {
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
int r; int r;
/* FIXME: check context uuid matches the dm-crypt device uuid */ /* FIXME: check context uuid matches the dm-crypt device uuid */
if (!passphrase || !name) if (!passphrase || !name)
return -EINVAL; return -EINVAL;
log_dbg("Resuming volume %s.", name); log_dbg(cd, "Resuming volume %s.", name);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
r = dm_status_suspended(cd, name); r = dm_status_suspended(cd, name);
if (r < 0) if (r < 0)
return r; return r;
if (!r) { if (!r) {
log_err(cd, _("Volume %s is not suspended."), name); log_err(cd, _("Volume %s is not suspended."), name);
skipping to change at line 2488 skipping to change at line 3016
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
char *passphrase_read = NULL; char *passphrase_read = NULL;
size_t passphrase_size_read; size_t passphrase_size_read;
int r; int r;
/* FIXME: check context uuid matches the dm-crypt device uuid */ /* FIXME: check context uuid matches the dm-crypt device uuid */
if (!name || !keyfile) if (!name || !keyfile)
return -EINVAL; return -EINVAL;
log_dbg("Resuming volume %s.", name); log_dbg(cd, "Resuming volume %s.", name);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
r = dm_status_suspended(cd, name); r = dm_status_suspended(cd, name);
if (r < 0) if (r < 0)
return r; return r;
if (!r) { if (!r) {
log_err(cd, _("Volume %s is not suspended."), name); log_err(cd, _("Volume %s is not suspended."), name);
skipping to change at line 2574 skipping to change at line 3102
int keyslot, // -1 any int keyslot, // -1 any
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
const char *new_passphrase, const char *new_passphrase,
size_t new_passphrase_size) size_t new_passphrase_size)
{ {
int digest, r, active_slots; int digest, r, active_slots;
struct luks2_keyslot_params params; struct luks2_keyslot_params params;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
log_dbg("Adding new keyslot, existing passphrase %sprovided," log_dbg(cd, "Adding new keyslot, existing passphrase %sprovided,"
"new passphrase %sprovided.", "new passphrase %sprovided.",
passphrase ? "" : "not ", new_passphrase ? "" : "not "); passphrase ? "" : "not ", new_passphrase ? "" : "not ");
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
if (!passphrase || !new_passphrase) if (!passphrase || !new_passphrase)
return -EINVAL; return -EINVAL;
r = keyslot_verify_or_find_empty(cd, &keyslot); r = keyslot_verify_or_find_empty(cd, &keyslot);
skipping to change at line 2624 skipping to change at line 3152
goto out; goto out;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
r = LUKS_set_key(keyslot, CONST_CAST(char*)new_passphrase, r = LUKS_set_key(keyslot, CONST_CAST(char*)new_passphrase,
new_passphrase_size, &cd->u.luks1.hdr, vk, cd); new_passphrase_size, &cd->u.luks1.hdr, vk, cd);
else { else {
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DE FAULT_SEGMENT, vk); r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DE FAULT_SEGMENT, vk);
digest = r; digest = r;
if (r >= 0) if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk ->keylength, &params); r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &p arams);
if (r >= 0) if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, di gest, 1, 0); r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, di gest, 1, 0);
if (r >= 0) if (r >= 0)
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot, r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
CONST_CAST(char*)new_passphrase, CONST_CAST(char*)new_passphrase,
new_passphrase_size, vk, &params) ; new_passphrase_size, vk, &params) ;
} }
skipping to change at line 2663 skipping to change at line 3191
const char *new_passphrase, const char *new_passphrase,
size_t new_passphrase_size) size_t new_passphrase_size)
{ {
int digest = -1, r; int digest = -1, r;
struct luks2_keyslot_params params; struct luks2_keyslot_params params;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
if (!passphrase || !new_passphrase) if (!passphrase || !new_passphrase)
return -EINVAL; return -EINVAL;
log_dbg("Changing passphrase from old keyslot %d to new %d.", log_dbg(cd, "Changing passphrase from old keyslot %d to new %d.",
keyslot_old, keyslot_new); keyslot_old, keyslot_new);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
r = LUKS_open_key_with_hdr(keyslot_old, passphrase, passphrase_si ze, r = LUKS_open_key_with_hdr(keyslot_old, passphrase, passphrase_si ze,
&cd->u.luks1.hdr, &vk, cd); &cd->u.luks1.hdr, &vk, cd);
else if (isLUKS2(cd->type)) { else if (isLUKS2(cd->type)) {
r = LUKS2_keyslot_open(cd, keyslot_old, CRYPT_ANY_SEGMENT, passph rase, passphrase_size, &vk); r = LUKS2_keyslot_open(cd, keyslot_old, CRYPT_ANY_SEGMENT, passph rase, passphrase_size, &vk);
/* will fail for keyslots w/o digest. fix if supported in a futur e */ /* will fail for keyslots w/o digest. fix if supported in a futur e */
if (r >= 0) { if (r >= 0) {
digest = LUKS2_digest_by_keyslot(cd, &cd->u.luks2.hdr, r) ; digest = LUKS2_digest_by_keyslot(&cd->u.luks2.hdr, r);
if (digest < 0) if (digest < 0)
r = -EINVAL; r = -EINVAL;
} }
} else } else
r = -EINVAL; r = -EINVAL;
if (r < 0) if (r < 0)
goto out; goto out;
if (keyslot_old != CRYPT_ANY_SLOT && keyslot_old != r) { if (keyslot_old != CRYPT_ANY_SLOT && keyslot_old != r) {
log_dbg("Keyslot mismatch."); log_dbg(cd, "Keyslot mismatch.");
goto out; goto out;
} }
keyslot_old = r; keyslot_old = r;
if (keyslot_new == CRYPT_ANY_SLOT) { if (keyslot_new == CRYPT_ANY_SLOT) {
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr); keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
else if (isLUKS2(cd->type)) else if (isLUKS2(cd->type))
keyslot_new = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr, "luks2"); // FIXME keyslot_new = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr, "luks2"); // FIXME
if (keyslot_new < 0) if (keyslot_new < 0)
keyslot_new = keyslot_old; keyslot_new = keyslot_old;
} }
log_dbg("Key change, old slot %d, new slot %d.", keyslot_old, keyslot_new ); log_dbg(cd, "Key change, old slot %d, new slot %d.", keyslot_old, keyslot _new);
if (isLUKS1(cd->type)) { if (isLUKS1(cd->type)) {
if (keyslot_old == keyslot_new) { if (keyslot_old == keyslot_new) {
log_dbg("Key slot %d is going to be overwritten.", keyslo t_old); log_dbg(cd, "Key slot %d is going to be overwritten.", ke yslot_old);
(void)crypt_keyslot_destroy(cd, keyslot_old); (void)crypt_keyslot_destroy(cd, keyslot_old);
} }
r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size , r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size ,
&cd->u.luks1.hdr, vk, cd); &cd->u.luks1.hdr, vk, cd);
} else if (isLUKS2(cd->type)) { } else if (isLUKS2(cd->type)) {
r = LUKS2_get_keyslot_params(&cd->u.luks2.hdr, keyslot_old, &para ms); r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r) if (r)
goto out; goto out;
if (keyslot_old != keyslot_new) { if (keyslot_old != keyslot_new) {
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot_new , digest, 1, 0); r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot_new , digest, 1, 0);
if (r < 0) if (r < 0)
goto out; goto out;
} else { } else {
log_dbg("Key slot %d is going to be overwritten.", keyslo t_old); log_dbg(cd, "Key slot %d is going to be overwritten.", ke yslot_old);
/* FIXME: improve return code so that we can detect area is damaged */ /* FIXME: improve return code so that we can detect area is damaged */
r = LUKS2_keyslot_wipe(cd, &cd->u.luks2.hdr, keyslot_old, 1); r = LUKS2_keyslot_wipe(cd, &cd->u.luks2.hdr, keyslot_old, 1);
if (r) { if (r) {
/* (void)crypt_keyslot_destroy(cd, keyslot_old); */ /* (void)crypt_keyslot_destroy(cd, keyslot_old); */
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
} }
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr,
skipping to change at line 2765 skipping to change at line 3294
{ {
int digest, r, active_slots; int digest, r, active_slots;
size_t passwordLen, new_passwordLen; size_t passwordLen, new_passwordLen;
struct luks2_keyslot_params params; struct luks2_keyslot_params params;
char *password = NULL, *new_password = NULL; char *password = NULL, *new_password = NULL;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
if (!keyfile || !new_keyfile) if (!keyfile || !new_keyfile)
return -EINVAL; return -EINVAL;
log_dbg("Adding new keyslot, existing keyfile %s, new keyfile %s.", log_dbg(cd, "Adding new keyslot, existing keyfile %s, new keyfile %s.",
keyfile, new_keyfile); keyfile, new_keyfile);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
r = keyslot_verify_or_find_empty(cd, &keyslot); r = keyslot_verify_or_find_empty(cd, &keyslot);
if (r) if (r)
return r; return r;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
skipping to change at line 2819 skipping to change at line 3348
goto out; goto out;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
r = LUKS_set_key(keyslot, new_password, new_passwordLen, r = LUKS_set_key(keyslot, new_password, new_passwordLen,
&cd->u.luks1.hdr, vk, cd); &cd->u.luks1.hdr, vk, cd);
else { else {
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DE FAULT_SEGMENT, vk); r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DE FAULT_SEGMENT, vk);
digest = r; digest = r;
if (r >= 0) if (r >= 0)
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk ->keylength, &params); r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &p arams);
if (r >= 0) if (r >= 0)
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, di gest, 1, 0); r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, di gest, 1, 0);
if (r >= 0) if (r >= 0)
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot, r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
new_password, new_passwordLen, vk , &params); new_password, new_passwordLen, vk , &params);
} }
out: out:
crypt_safe_free(password); crypt_safe_free(password);
skipping to change at line 2878 skipping to change at line 3407
size_t volume_key_size, size_t volume_key_size,
const char *passphrase, const char *passphrase,
size_t passphrase_size) size_t passphrase_size)
{ {
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
int r; int r;
if (!passphrase) if (!passphrase)
return -EINVAL; return -EINVAL;
log_dbg("Adding new keyslot %d using volume key.", keyslot); log_dbg(cd, "Adding new keyslot %d using volume key.", keyslot);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
if (isLUKS2(cd->type)) if (isLUKS2(cd->type))
return crypt_keyslot_add_by_key(cd, keyslot, return crypt_keyslot_add_by_key(cd, keyslot,
volume_key, volume_key_size, passphrase, volume_key, volume_key_size, passphrase,
passphrase_size, 0); passphrase_size, 0);
r = keyslot_verify_or_find_empty(cd, &keyslot); r = keyslot_verify_or_find_empty(cd, &keyslot);
skipping to change at line 2916 skipping to change at line 3445
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
return (r < 0) ? r : keyslot; return (r < 0) ? r : keyslot;
} }
int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot) int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot)
{ {
crypt_keyslot_info ki; crypt_keyslot_info ki;
int r; int r;
log_dbg("Destroying keyslot %d.", keyslot); log_dbg(cd, "Destroying keyslot %d.", keyslot);
if ((r = _onlyLUKS(cd, CRYPT_CD_UNRESTRICTED))) if ((r = _onlyLUKS(cd, CRYPT_CD_UNRESTRICTED)))
return r; return r;
ki = crypt_keyslot_status(cd, keyslot); ki = crypt_keyslot_status(cd, keyslot);
if (ki == CRYPT_SLOT_INVALID) { if (ki == CRYPT_SLOT_INVALID) {
log_err(cd, _("Key slot %d is invalid."), keyslot); log_err(cd, _("Key slot %d is invalid."), keyslot);
return -EINVAL; return -EINVAL;
} }
skipping to change at line 2955 skipping to change at line 3484
/* FIXME: check real header size */ /* FIXME: check real header size */
if (crypt_get_data_offset(cd) == 0) { if (crypt_get_data_offset(cd) == 0) {
log_err(cd, _("Device header overlaps with data area.")); log_err(cd, _("Device header overlaps with data area."));
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static int check_devices(struct crypt_device *cd, const char *name, const char *
iname, uint32_t *flags)
{
int r;
if (!flags || !name)
return -EINVAL;
if (iname) {
r = dm_status_device(cd, iname);
if (r >= 0 && !(*flags & CRYPT_ACTIVATE_REFRESH))
return -EBUSY;
if (r < 0 && r != -ENODEV)
return r;
if (r == -ENODEV)
*flags &= ~CRYPT_ACTIVATE_REFRESH;
}
r = dm_status_device(cd, name);
if (r >= 0 && !(*flags & CRYPT_ACTIVATE_REFRESH))
return -EBUSY;
if (r < 0 && r != -ENODEV)
return r;
if (r == -ENODEV)
*flags &= ~CRYPT_ACTIVATE_REFRESH;
return 0;
}
static int _create_device_with_integrity(struct crypt_device *cd,
const char *type, const char *name, const char *iname,
const char *ipath, struct crypt_dm_active_device *dmd,
struct crypt_dm_active_device *dmdi)
{
int r;
enum devcheck device_check;
struct dm_target *tgt;
struct device *device = NULL;
if (!single_segment(dmd))
return -EINVAL;
tgt = &dmd->segment;
if (tgt->type != DM_CRYPT)
return -EINVAL;
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_EXCL;
r = INTEGRITY_activate_dmd_device(cd, iname, dmdi);
if (r)
return r;
r = device_alloc(cd, &device, ipath);
if (r < 0)
goto out;
tgt->data_device = device;
r = device_block_adjust(cd, tgt->data_device, device_check,
tgt->u.crypt.offset, &dmd->size, &dmd->flags);
if (!r)
r = dm_create_device(cd, name, type, dmd);
out:
if (r < 0)
dm_remove_device(cd, iname, 0);
device_free(cd, device);
return r;
}
int create_or_reload_device(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd)
{
int r;
enum devcheck device_check;
struct dm_target *tgt;
if (!type || !name || !single_segment(dmd))
return -EINVAL;
tgt = &dmd->segment;
if (tgt->type != DM_CRYPT)
return -EINVAL;
/* drop CRYPT_ACTIVATE_REFRESH flag if any device is inactive */
r = check_devices(cd, name, NULL, &dmd->flags);
if (r)
return r;
if (dmd->flags & CRYPT_ACTIVATE_REFRESH)
r = _reload_device(cd, name, dmd);
else {
device_check = dmd->flags & CRYPT_ACTIVATE_SHARED ? DEV_OK : DEV_
EXCL;
r = device_block_adjust(cd, tgt->data_device, device_check,
tgt->u.crypt.offset, &dmd->size, &dmd->fl
ags);
if (!r) {
tgt->size = dmd->size;
r = dm_create_device(cd, name, type, dmd);
}
}
return r;
}
int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *
name,
const char *type, struct crypt_dm_active_device *dmd,
struct crypt_dm_active_device *dmdi)
{
int r;
const char *iname = NULL;
char *ipath = NULL;
if (!type || !name || !dmd || !dmdi)
return -EINVAL;
if (asprintf(&ipath, "%s/%s_dif", dm_get_dir(), name) < 0)
return -ENOMEM;
iname = ipath + strlen(dm_get_dir()) + 1;
/* drop CRYPT_ACTIVATE_REFRESH flag if any device is inactive */
r = check_devices(cd, name, iname, &dmd->flags);
if (r)
goto out;
if (dmd->flags & CRYPT_ACTIVATE_REFRESH)
r = _reload_device_with_integrity(cd, name, iname, ipath, dmd, dm
di);
else
r = _create_device_with_integrity(cd, type, name, iname, ipath, d
md, dmdi);
out:
free(ipath);
return r;
}
/* /*
* Activation/deactivation of a device * Activation/deactivation of a device
*/ */
static int _activate_by_passphrase(struct crypt_device *cd, static int _activate_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
int keyslot, int keyslot,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
uint32_t flags) uint32_t flags)
{ {
skipping to change at line 3053 skipping to change at line 3716
if (!r && name) if (!r && name)
r = LOOPAES_activate(cd, name, cd->u.loopaes.cipher, key_count, r = LOOPAES_activate(cd, name, cd->u.loopaes.cipher, key_count,
vk, flags); vk, flags);
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
return r; return r;
} }
static int _activate_check_status(struct crypt_device *cd, const char *name) static int _activate_check_status(struct crypt_device *cd, const char *name, uns igned reload)
{ {
crypt_status_info ci; crypt_status_info ci;
if (!name) if (!name)
return 0; return 0;
ci = crypt_status(cd, name); ci = crypt_status(cd, name);
if (ci == CRYPT_INVALID) { if (ci == CRYPT_INVALID) {
log_err(cd, _("Cannot use device %s, name is invalid or still in use."), name); log_err(cd, _("Cannot use device %s, name is invalid or still in use."), name);
return -EINVAL; return -EINVAL;
} else if (ci >= CRYPT_ACTIVE) { } else if (ci >= CRYPT_ACTIVE && !reload) {
log_err(cd, _("Device %s already exists."), name); log_err(cd, _("Device %s already exists."), name);
return -EEXIST; return -EEXIST;
} }
return 0; return 0;
} }
// activation/deactivation of device mapping // activation/deactivation of device mapping
int crypt_activate_by_passphrase(struct crypt_device *cd, int crypt_activate_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
int keyslot, int keyslot,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
uint32_t flags) uint32_t flags)
{ {
int r; int r;
if (!cd || !passphrase) if (!cd || !passphrase || (!name && (flags & CRYPT_ACTIVATE_REFRESH)))
return -EINVAL; return -EINVAL;
log_dbg("%s volume %s [keyslot %d] using passphrase.", log_dbg(cd, "%s volume %s [keyslot %d] using passphrase.",
name ? "Activating" : "Checking", name ?: "passphrase", name ? "Activating" : "Checking", name ?: "passphrase",
keyslot); keyslot);
r = _activate_check_status(cd, name); r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0) if (r < 0)
return r; return r;
return _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_ size, flags); return _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_ size, flags);
} }
int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd, int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
const char *name, const char *name,
int keyslot, int keyslot,
const char *keyfile, const char *keyfile,
skipping to change at line 3112 skipping to change at line 3775
uint32_t flags) uint32_t flags)
{ {
char *passphrase_read = NULL; char *passphrase_read = NULL;
size_t passphrase_size_read; size_t passphrase_size_read;
int r; int r;
if (!cd || !keyfile || if (!cd || !keyfile ||
((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd ))) ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd )))
return -EINVAL; return -EINVAL;
log_dbg("%s volume %s [keyslot %d] using keyfile %s.", log_dbg(cd, "%s volume %s [keyslot %d] using keyfile %s.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot, keyfile); name ? "Activating" : "Checking", name ?: "passphrase", keyslot, keyfile);
r = _activate_check_status(cd, name); r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0) if (r < 0)
return r; return r;
r = crypt_keyfile_device_read(cd, keyfile, r = crypt_keyfile_device_read(cd, keyfile,
&passphrase_read, &passphrase_size_read, &passphrase_read, &passphrase_size_read,
keyfile_offset, keyfile_size, 0); keyfile_offset, keyfile_size, 0);
if (r < 0) if (r < 0)
goto out; goto out;
if (isLOOPAES(cd->type)) if (isLOOPAES(cd->type))
skipping to change at line 3171 skipping to change at line 3834
size_t volume_key_size, size_t volume_key_size,
uint32_t flags) uint32_t flags)
{ {
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
int r; int r;
if (!cd || if (!cd ||
((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd ))) ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd )))
return -EINVAL; return -EINVAL;
log_dbg("%s volume %s by volume key.", name ? "Activating" : "Checking", log_dbg(cd, "%s volume %s by volume key.", name ? "Activating" : "Checkin g",
name ?: ""); name ?: "");
r = _activate_check_status(cd, name); r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0) if (r < 0)
return r; return r;
r = _check_header_data_overlap(cd, name); r = _check_header_data_overlap(cd, name);
if (r < 0) if (r < 0)
return r; return r;
/* use key directly, no hash */ /* use key directly, no hash */
if (isPLAIN(cd->type)) { if (isPLAIN(cd->type)) {
if (!name) if (!name)
skipping to change at line 3306 skipping to change at line 3969
return r; return r;
} }
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags) int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
{ {
char *key_desc; char *key_desc;
struct crypt_device *fake_cd = NULL; struct crypt_device *fake_cd = NULL;
const char *namei = NULL; const char *namei = NULL;
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd = {};
int r; int r;
struct dm_target *tgt = &dmd.segment;
uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_HOLDERS; uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_HOLDERS;
if (!name) if (!name)
return -EINVAL; return -EINVAL;
log_dbg("Deactivating volume %s.", name); log_dbg(cd, "Deactivating volume %s.", name);
if (!cd) { if (!cd) {
r = crypt_init_by_name(&fake_cd, name); r = crypt_init_by_name(&fake_cd, name);
if (r < 0) if (r < 0)
return r; return r;
cd = fake_cd; cd = fake_cd;
} }
/* skip holders detection and early abort when some flags raised */ /* skip holders detection and early abort when some flags raised */
if (flags & (CRYPT_DEACTIVATE_FORCE | CRYPT_DEACTIVATE_DEFERRED)) if (flags & (CRYPT_DEACTIVATE_FORCE | CRYPT_DEACTIVATE_DEFERRED))
skipping to change at line 3334 skipping to change at line 3998
switch (crypt_status(cd, name)) { switch (crypt_status(cd, name)) {
case CRYPT_ACTIVE: case CRYPT_ACTIVE:
case CRYPT_BUSY: case CRYPT_BUSY:
r = dm_query_device(cd, name, get_flags, &dmd); r = dm_query_device(cd, name, get_flags, &dmd);
if (r >= 0) { if (r >= 0) {
if (dmd.holders) { if (dmd.holders) {
log_err(cd, _("Device %s is still in use. "), name); log_err(cd, _("Device %s is still in use. "), name);
r = -EBUSY; r = -EBUSY;
break; break;
} }
if (isLUKS2(cd->type) && crypt_get_integrity_tag_ if (isLUKS2(cd->type) && single_segment(&dmd) &&
size(cd)) tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
namei = device_dm_name(dmd.data_device); namei = device_dm_name(tgt->data_device);
} }
key_desc = crypt_get_device_key_description(name); key_desc = crypt_get_device_key_description(cd, name);
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
r = TCRYPT_deactivate(cd, name, flags); r = TCRYPT_deactivate(cd, name, flags);
else else
r = dm_remove_device(cd, name, flags); r = dm_remove_device(cd, name, flags);
if (r < 0 && crypt_status(cd, name) == CRYPT_BUSY) { if (r < 0 && crypt_status(cd, name) == CRYPT_BUSY) {
log_err(cd, _("Device %s is still in use."), name ); log_err(cd, _("Device %s is still in use."), name );
r = -EBUSY; r = -EBUSY;
} else if (namei) { } else if (namei) {
log_dbg("Deactivating integrity device %s.", name i); log_dbg(cd, "Deactivating integrity device %s.", namei);
r = dm_remove_device(cd, namei, 0); r = dm_remove_device(cd, namei, 0);
} }
if (!r) if (!r)
crypt_drop_keyring_key(cd, key_desc); crypt_drop_keyring_key(cd, key_desc);
free(key_desc); free(key_desc);
break; break;
case CRYPT_INACTIVE: case CRYPT_INACTIVE:
log_err(cd, _("Device %s is not active."), name); log_err(cd, _("Device %s is not active."), name);
r = -ENODEV; r = -ENODEV;
break; break;
default: default:
log_err(cd, _("Invalid device %s."), name); log_err(cd, _("Invalid device %s."), name);
r = -EINVAL; r = -EINVAL;
} }
device_free(dmd.data_device); dm_targets_free(cd, &dmd);
crypt_free(fake_cd); crypt_free(fake_cd);
return r; return r;
} }
int crypt_deactivate(struct crypt_device *cd, const char *name) int crypt_deactivate(struct crypt_device *cd, const char *name)
{ {
return crypt_deactivate_by_name(cd, name, 0); return crypt_deactivate_by_name(cd, name, 0);
} }
int crypt_get_active_device(struct crypt_device *cd, const char *name, int crypt_get_active_device(struct crypt_device *cd, const char *name,
struct crypt_active_device *cad) struct crypt_active_device *cad)
{ {
struct crypt_dm_active_device dmd = {}, dmdi = {};
const char *namei = NULL;
int r; int r;
struct crypt_dm_active_device dmd, dmdi = {};
const char *namei = NULL;
struct dm_target *tgt = &dmd.segment;
if (!cd || !name || !cad) if (!cd || !name || !cad)
return -EINVAL; return -EINVAL;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE, &dmd); r = dm_query_device(cd, name, DM_ACTIVE_DEVICE, &dmd);
if (r < 0) if (r < 0)
return r; return r;
if (dmd.target != DM_CRYPT && if (!single_segment(&dmd)) {
dmd.target != DM_VERITY && log_dbg(cd, "Unexpected multi-segment device detected.");
dmd.target != DM_INTEGRITY) r = -ENOTSUP;
return -ENOTSUP; goto out;
}
if (tgt->type != DM_CRYPT &&
tgt->type != DM_VERITY &&
tgt->type != DM_INTEGRITY) {
r = -ENOTSUP;
goto out;
}
/* For LUKS2 with integrity we need flags from underlying dm-integrity */ /* For LUKS2 with integrity we need flags from underlying dm-integrity */
if (isLUKS2(cd->type) && crypt_get_integrity_tag_size(cd)) { if (isLUKS2(cd->type) && crypt_get_integrity_tag_size(cd)) {
namei = device_dm_name(dmd.data_device); namei = device_dm_name(tgt->data_device);
if (namei && dm_query_device(cd, namei, 0, &dmdi) >= 0) if (namei && dm_query_device(cd, namei, 0, &dmdi) >= 0)
dmd.flags |= dmdi.flags; dmd.flags |= dmdi.flags;
} }
device_free(dmd.data_device);
if (cd && isTCRYPT(cd->type)) { if (cd && isTCRYPT(cd->type)) {
cad->offset = TCRYPT_get_data_offset(cd, &cd->u.tcrypt.hdr, & cd->u.tcrypt.params); cad->offset = TCRYPT_get_data_offset(cd, &cd->u.tcrypt.hdr, & cd->u.tcrypt.params);
cad->iv_offset = TCRYPT_get_iv_offset(cd, &cd->u.tcrypt.hdr, &cd ->u.tcrypt.params); cad->iv_offset = TCRYPT_get_iv_offset(cd, &cd->u.tcrypt.hdr, &cd ->u.tcrypt.params);
} else if (dmd.target == DM_CRYPT) { } else if (tgt->type == DM_CRYPT) {
cad->offset = dmd.u.crypt.offset; cad->offset = tgt->u.crypt.offset;
cad->iv_offset = dmd.u.crypt.iv_offset; cad->iv_offset = tgt->u.crypt.iv_offset;
} }
cad->size = dmd.size; cad->size = dmd.size;
cad->flags = dmd.flags; cad->flags = dmd.flags;
return 0; r = 0;
out:
dm_targets_free(cd, &dmd);
dm_targets_free(cd, &dmdi);
return r;
} }
uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd, const char *name) uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd, const char *name)
{ {
struct crypt_dm_active_device dmd; struct crypt_dm_active_device dmd;
uint64_t failures = 0; uint64_t failures = 0;
if (!name) if (!name)
return 0; return 0;
/* FIXME: LUKS2 / dm-crypt does not provide this count. */ /* FIXME: LUKS2 / dm-crypt does not provide this count. */
if (dm_query_device(cd, name, 0, &dmd) < 0) if (dm_query_device(cd, name, 0, &dmd) < 0)
return 0; return 0;
if (dmd.target == DM_INTEGRITY && if (single_segment(&dmd) && dmd.segment.type == DM_INTEGRITY)
!dm_status_integrity_failures(cd, name, &failures)) (void)dm_status_integrity_failures(cd, name, &failures);
return failures;
return 0; dm_targets_free(cd, &dmd);
return failures;
} }
/* /*
* Volume key handling * Volume key handling
*/ */
int crypt_volume_key_get(struct crypt_device *cd, int crypt_volume_key_get(struct crypt_device *cd,
int keyslot, int keyslot,
char *volume_key, char *volume_key,
size_t *volume_key_size, size_t *volume_key_size,
const char *passphrase, const char *passphrase,
skipping to change at line 3461 skipping to change at line 4139
if (crypt_fips_mode() && if (crypt_fips_mode() &&
!crypt_cipher_wrapped_key(crypt_get_cipher(cd), crypt_get_cipher_mode (cd))) { !crypt_cipher_wrapped_key(crypt_get_cipher(cd), crypt_get_cipher_mode (cd))) {
if (!isLUKS2(cd->type) || keyslot == CRYPT_ANY_SLOT || if (!isLUKS2(cd->type) || keyslot == CRYPT_ANY_SLOT ||
!LUKS2_keyslot_for_segment(&cd->u.luks2.hdr, keyslot, CRYPT_D EFAULT_SEGMENT)) { !LUKS2_keyslot_for_segment(&cd->u.luks2.hdr, keyslot, CRYPT_D EFAULT_SEGMENT)) {
log_err(cd, _("Function not available in FIPS mode.")); log_err(cd, _("Function not available in FIPS mode."));
return -EACCES; return -EACCES;
} }
} }
if (isLUKS2(cd->type) && keyslot != CRYPT_ANY_SLOT) if (isLUKS2(cd->type) && keyslot != CRYPT_ANY_SLOT)
key_len = LUKS2_get_keyslot_key_size(&cd->u.luks2.hdr, keyslot); key_len = LUKS2_get_keyslot_stored_key_size(&cd->u.luks2.hdr, key slot);
else else
key_len = crypt_get_volume_key_size(cd); key_len = crypt_get_volume_key_size(cd);
if (key_len < 0) if (key_len < 0)
return -EINVAL; return -EINVAL;
if (key_len > (int)*volume_key_size) { if (key_len > (int)*volume_key_size) {
log_err(cd, _("Volume key buffer too small.")); log_err(cd, _("Volume key buffer too small."));
return -ENOMEM; return -ENOMEM;
} }
skipping to change at line 3537 skipping to change at line 4215
* RNG and memory locking * RNG and memory locking
*/ */
void crypt_set_rng_type(struct crypt_device *cd, int rng_type) void crypt_set_rng_type(struct crypt_device *cd, int rng_type)
{ {
if (!cd) if (!cd)
return; return;
switch (rng_type) { switch (rng_type) {
case CRYPT_RNG_URANDOM: case CRYPT_RNG_URANDOM:
case CRYPT_RNG_RANDOM: case CRYPT_RNG_RANDOM:
log_dbg("RNG set to %d (%s).", rng_type, rng_type ? "random" : "u random"); log_dbg(cd, "RNG set to %d (%s).", rng_type, rng_type ? "random" : "urandom");
cd->rng_type = rng_type; cd->rng_type = rng_type;
} }
} }
int crypt_get_rng_type(struct crypt_device *cd) int crypt_get_rng_type(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return -EINVAL; return -EINVAL;
return cd->rng_type; return cd->rng_type;
skipping to change at line 3566 skipping to change at line 4244
* Reporting * Reporting
*/ */
crypt_status_info crypt_status(struct crypt_device *cd, const char *name) crypt_status_info crypt_status(struct crypt_device *cd, const char *name)
{ {
int r; int r;
if (!name) if (!name)
return CRYPT_INVALID; return CRYPT_INVALID;
if (!cd) if (!cd)
dm_backend_init(); dm_backend_init(cd);
r = dm_status_device(cd, name); r = dm_status_device(cd, name);
if (!cd) if (!cd)
dm_backend_exit(); dm_backend_exit(cd);
if (r < 0 && r != -ENODEV) if (r < 0 && r != -ENODEV)
return CRYPT_INVALID; return CRYPT_INVALID;
if (r == 0) if (r == 0)
return CRYPT_ACTIVE; return CRYPT_ACTIVE;
if (r > 0) if (r > 0)
return CRYPT_BUSY; return CRYPT_BUSY;
skipping to change at line 3679 skipping to change at line 4357
return _verity_dump(cd); return _verity_dump(cd);
else if (isTCRYPT(cd->type)) else if (isTCRYPT(cd->type))
return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params); return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
else if (isINTEGRITY(cd->type)) else if (isINTEGRITY(cd->type))
return INTEGRITY_dump(cd, crypt_data_device(cd), 0); return INTEGRITY_dump(cd, crypt_data_device(cd), 0);
log_err(cd, _("Dump operation is not supported for this device type.")); log_err(cd, _("Dump operation is not supported for this device type."));
return -EINVAL; return -EINVAL;
} }
/* internal only */
const char *crypt_get_cipher_spec(struct crypt_device *cd)
{
if (!cd)
return NULL;
else if (isLUKS2(cd->type))
return LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
else if (isLUKS1(cd->type))
return cd->u.luks1.cipher_spec;
else if (isPLAIN(cd->type))
return cd->u.plain.cipher_spec;
else if (isLOOPAES(cd->type))
return cd->u.loopaes.cipher_spec;
else if (!cd->type && !_init_by_name_crypt_none(cd))
return cd->u.none.cipher_spec;
return NULL;
}
const char *crypt_get_cipher(struct crypt_device *cd) const char *crypt_get_cipher(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return NULL; return NULL;
if (isPLAIN(cd->type)) if (isPLAIN(cd->type))
return cd->u.plain.cipher; return cd->u.plain.cipher;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return cd->u.luks1.hdr.cipherName; return cd->u.luks1.hdr.cipherName;
if (isLUKS2(cd->type)) if (isLUKS2(cd->type)) {
if (crypt_parse_name_and_mode(LUKS2_get_cipher(&cd->u.luks2.hdr,
CRYPT_DEFAULT_SEGMENT),
cd->u.luks2.cipher, NULL, cd->u.luk
s2.cipher_mode))
return NULL;
return cd->u.luks2.cipher; return cd->u.luks2.cipher;
}
if (isLOOPAES(cd->type)) if (isLOOPAES(cd->type))
return cd->u.loopaes.cipher; return cd->u.loopaes.cipher;
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
return cd->u.tcrypt.params.cipher; return cd->u.tcrypt.params.cipher;
if (!cd->type && !_init_by_name_crypt_none(cd)) if (!cd->type && !_init_by_name_crypt_none(cd))
return cd->u.none.cipher; return cd->u.none.cipher;
skipping to change at line 3716 skipping to change at line 4417
{ {
if (!cd) if (!cd)
return NULL; return NULL;
if (isPLAIN(cd->type)) if (isPLAIN(cd->type))
return cd->u.plain.cipher_mode; return cd->u.plain.cipher_mode;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return cd->u.luks1.hdr.cipherMode; return cd->u.luks1.hdr.cipherMode;
if (isLUKS2(cd->type)) if (isLUKS2(cd->type)) {
if (crypt_parse_name_and_mode(LUKS2_get_cipher(&cd->u.luks2.hdr,
CRYPT_DEFAULT_SEGMENT),
cd->u.luks2.cipher, NULL, cd->u.luk
s2.cipher_mode))
return NULL;
return cd->u.luks2.cipher_mode; return cd->u.luks2.cipher_mode;
}
if (isLOOPAES(cd->type)) if (isLOOPAES(cd->type))
return cd->u.loopaes.cipher_mode; return cd->u.loopaes.cipher_mode;
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
return cd->u.tcrypt.params.mode; return cd->u.tcrypt.params.mode;
if (!cd->type && !_init_by_name_crypt_none(cd)) if (!cd->type && !_init_by_name_crypt_none(cd))
return cd->u.none.cipher_mode; return cd->u.none.cipher_mode;
skipping to change at line 3816 skipping to change at line 4521
if (!cd) if (!cd)
return NULL; return NULL;
path = device_block_path(cd->device); path = device_block_path(cd->device);
if (!path) if (!path)
path = device_path(cd->device); path = device_path(cd->device);
return path; return path;
} }
const char *crypt_get_metadata_device_name(struct crypt_device *cd)
{
const char *path;
if (!cd || !cd->metadata_device)
return NULL;
path = device_block_path(cd->metadata_device);
if (!path)
path = device_path(cd->metadata_device);
return path;
}
int crypt_get_volume_key_size(struct crypt_device *cd) int crypt_get_volume_key_size(struct crypt_device *cd)
{ {
int r; int r;
if (!cd) if (!cd)
return 0; return 0;
if (isPLAIN(cd->type)) if (isPLAIN(cd->type))
return cd->u.plain.key_size; return cd->u.plain.key_size;
skipping to change at line 3863 skipping to change at line 4582
if (!cd || !isLUKS(cd->type)) if (!cd || !isLUKS(cd->type))
return -EINVAL; return -EINVAL;
if (keyslot < 0 || keyslot >= crypt_keyslot_max(cd->type)) if (keyslot < 0 || keyslot >= crypt_keyslot_max(cd->type))
return -EINVAL; return -EINVAL;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return cd->u.luks1.hdr.keyBytes; return cd->u.luks1.hdr.keyBytes;
if (isLUKS2(cd->type)) if (isLUKS2(cd->type))
return LUKS2_get_keyslot_key_size(&cd->u.luks2.hdr, keyslot); return LUKS2_get_keyslot_stored_key_size(&cd->u.luks2.hdr, keyslo
t);
return -EINVAL;
}
int crypt_keyslot_set_encryption(struct crypt_device *cd,
const char *cipher,
size_t key_size)
{
if (!cd || !cipher || ! key_size || !isLUKS2(cd->type))
return -EINVAL;
if (LUKS2_keyslot_cipher_incompatible(cd, cipher))
return -EINVAL;
free(cd->u.luks2.keyslot_cipher);
cd->u.luks2.keyslot_cipher = strdup(cipher);
if (!cd->u.luks2.keyslot_cipher)
return -ENOMEM;
cd->u.luks2.keyslot_key_size = key_size;
return 0;
}
const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, s
ize_t *key_size)
{
const char *cipher;
if (!cd || !isLUKS(cd->type) || !key_size)
return NULL;
if (isLUKS1(cd->type)) {
if (keyslot != CRYPT_ANY_SLOT &&
LUKS_keyslot_info(&cd->u.luks1.hdr, keyslot) < CRYPT_SLOT_ACT
IVE)
return NULL;
*key_size = crypt_get_volume_key_size(cd);
return cd->u.luks1.cipher_spec;
}
if (keyslot != CRYPT_ANY_SLOT)
return LUKS2_get_keyslot_cipher(&cd->u.luks2.hdr, keyslot, key_si
ze);
/* Keyslot encryption was set through crypt_keyslot_set_encryption() */
if (cd->u.luks2.keyslot_cipher) {
*key_size = cd->u.luks2.keyslot_key_size;
return cd->u.luks2.keyslot_cipher;
}
/* Try to reuse volume encryption parameters */
cipher = LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
if (!LUKS2_keyslot_cipher_incompatible(cd, cipher)) {
*key_size = crypt_get_volume_key_size(cd);
return cipher;
}
/* Fallback to default LUKS2 keyslot encryption */
*key_size = DEFAULT_LUKS2_KEYSLOT_KEYBITS / 8;
return DEFAULT_LUKS2_KEYSLOT_CIPHER;
}
int crypt_keyslot_get_pbkdf(struct crypt_device *cd, int keyslot, struct crypt_p
bkdf_type *pbkdf)
{
if (!cd || !pbkdf || keyslot == CRYPT_ANY_SLOT)
return -EINVAL;
if (isLUKS1(cd->type))
return LUKS_keyslot_pbkdf(&cd->u.luks1.hdr, keyslot, pbkdf);
else if (isLUKS2(cd->type))
return LUKS2_keyslot_pbkdf(&cd->u.luks2.hdr, keyslot, pbkdf);
return -EINVAL; return -EINVAL;
} }
int crypt_set_data_offset(struct crypt_device *cd, uint64_t data_offset)
{
if (!cd)
return -EINVAL;
if (data_offset % (MAX_SECTOR_SIZE >> SECTOR_SHIFT)) {
log_err(cd, "Data offset is not multiple of %u bytes.", MAX_SECTO
R_SIZE);
return -EINVAL;
}
cd->data_offset = data_offset;
log_dbg(cd, "Data offset set to %" PRIu64 " (512-byte) sectors.", data_of
fset);
return 0;
}
int crypt_set_metadata_size(struct crypt_device *cd,
uint64_t metadata_size,
uint64_t keyslots_size)
{
if (!cd)
return -EINVAL;
if (cd->type && !isLUKS2(cd->type))
return -EINVAL;
if (metadata_size && LUKS2_check_metadata_area_size(metadata_size))
return -EINVAL;
if (keyslots_size && LUKS2_check_keyslots_area_size(keyslots_size))
return -EINVAL;
cd->metadata_size = metadata_size;
cd->keyslots_size = keyslots_size;
return 0;
}
int crypt_get_metadata_size(struct crypt_device *cd,
uint64_t *metadata_size,
uint64_t *keyslots_size)
{
uint64_t msize, ksize;
if (!cd)
return -EINVAL;
if (!cd->type) {
msize = cd->metadata_size;
ksize = cd->keyslots_size;
} else if (isLUKS1(cd->type)) {
msize = LUKS_ALIGN_KEYSLOTS;
ksize = LUKS_device_sectors(&cd->u.luks1.hdr) * SECTOR_SIZE - msi
ze;
} else if (isLUKS2(cd->type)) {
msize = LUKS2_metadata_size(cd->u.luks2.hdr.jobj);
ksize = LUKS2_keyslots_size(cd->u.luks2.hdr.jobj);
} else
return -EINVAL;
if (metadata_size)
*metadata_size = msize;
if (keyslots_size)
*keyslots_size = ksize;
return 0;
}
uint64_t crypt_get_data_offset(struct crypt_device *cd) uint64_t crypt_get_data_offset(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return 0; return 0;
if (isPLAIN(cd->type)) if (isPLAIN(cd->type))
return cd->u.plain.hdr.offset; return cd->u.plain.hdr.offset;
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return cd->u.luks1.hdr.payloadOffset; return cd->u.luks1.hdr.payloadOffset;
if (isLUKS2(cd->type)) if (isLUKS2(cd->type))
return LUKS2_get_data_offset(&cd->u.luks2.hdr); return LUKS2_get_data_offset(&cd->u.luks2.hdr);
if (isLOOPAES(cd->type)) if (isLOOPAES(cd->type))
return cd->u.loopaes.hdr.offset; return cd->u.loopaes.hdr.offset;
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
return TCRYPT_get_data_offset(cd, &cd->u.tcrypt.hdr, &cd->u.tcryp t.params); return TCRYPT_get_data_offset(cd, &cd->u.tcrypt.hdr, &cd->u.tcryp t.params);
return 0; return cd->data_offset;
} }
uint64_t crypt_get_iv_offset(struct crypt_device *cd) uint64_t crypt_get_iv_offset(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return 0; return 0;
if (isPLAIN(cd->type)) if (isPLAIN(cd->type))
return cd->u.plain.hdr.skip; return cd->u.plain.hdr.skip;
skipping to change at line 3964 skipping to change at line 4817
if (isLUKS2(cd->type)) if (isLUKS2(cd->type))
return LUKS2_keyslot_priority_get(cd, &cd->u.luks2.hdr, keyslot); return LUKS2_keyslot_priority_get(cd, &cd->u.luks2.hdr, keyslot);
return CRYPT_SLOT_PRIORITY_NORMAL; return CRYPT_SLOT_PRIORITY_NORMAL;
} }
int crypt_keyslot_set_priority(struct crypt_device *cd, int keyslot, crypt_keysl ot_priority priority) int crypt_keyslot_set_priority(struct crypt_device *cd, int keyslot, crypt_keysl ot_priority priority)
{ {
int r; int r;
log_dbg("Setting keyslot %d to priority %d.", keyslot, priority); log_dbg(cd, "Setting keyslot %d to priority %d.", keyslot, priority);
if (priority == CRYPT_SLOT_PRIORITY_INVALID) if (priority == CRYPT_SLOT_PRIORITY_INVALID)
return -EINVAL; return -EINVAL;
if (keyslot < 0 || keyslot >= crypt_keyslot_max(cd->type)) if (keyslot < 0 || keyslot >= crypt_keyslot_max(cd->type))
return -EINVAL; return -EINVAL;
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_keyslot_priority_set(cd, &cd->u.luks2.hdr, keyslot, priority , 1); return LUKS2_keyslot_priority_set(cd, &cd->u.luks2.hdr, keyslot, priority , 1);
} }
const char *crypt_get_type(struct crypt_device *cd) const char *crypt_get_type(struct crypt_device *cd)
{ {
return cd ? cd->type : NULL; return cd ? cd->type : NULL;
} }
const char *crypt_get_default_type(void)
{
return DEFAULT_LUKS_FORMAT;
}
int crypt_get_verity_info(struct crypt_device *cd, int crypt_get_verity_info(struct crypt_device *cd,
struct crypt_params_verity *vp) struct crypt_params_verity *vp)
{ {
if (!cd || !isVERITY(cd->type) || !vp) if (!cd || !isVERITY(cd->type) || !vp)
return -EINVAL; return -EINVAL;
vp->data_device = device_path(cd->device); vp->data_device = device_path(cd->device);
vp->hash_device = mdata_device_path(cd); vp->hash_device = mdata_device_path(cd);
vp->fec_device = device_path(cd->u.verity.fec_device); vp->fec_device = device_path(cd->u.verity.fec_device);
vp->fec_area_offset = cd->u.verity.hdr.fec_area_offset; vp->fec_area_offset = cd->u.verity.hdr.fec_area_offset;
skipping to change at line 4068 skipping to change at line 4926
const char *type, const char *type,
void *params) void *params)
{ {
struct luks_phdr hdr1; struct luks_phdr hdr1;
struct luks2_hdr hdr2; struct luks2_hdr hdr2;
int r; int r;
if (!type) if (!type)
return -EINVAL; return -EINVAL;
log_dbg("Converting LUKS device to type %s", type); log_dbg(cd, "Converting LUKS device to type %s", type);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
return r; return r;
if (isLUKS1(cd->type) && isLUKS2(type)) if (isLUKS1(cd->type) && isLUKS2(type))
r = LUKS2_luks1_to_luks2(cd, &cd->u.luks1.hdr, &hdr2); r = LUKS2_luks1_to_luks2(cd, &cd->u.luks1.hdr, &hdr2);
else if (isLUKS2(cd->type) && isLUKS1(type)) else if (isLUKS2(cd->type) && isLUKS1(type))
r = LUKS2_luks2_to_luks1(cd, &cd->u.luks2.hdr, &hdr1); r = LUKS2_luks2_to_luks1(cd, &cd->u.luks2.hdr, &hdr1);
else else
return -EINVAL; return -EINVAL;
skipping to change at line 4129 skipping to change at line 4987
} }
/* /*
* Token handling * Token handling
*/ */
int crypt_activate_by_token(struct crypt_device *cd, int crypt_activate_by_token(struct crypt_device *cd,
const char *name, int token, void *usrptr, uint32_t flags) const char *name, int token, void *usrptr, uint32_t flags)
{ {
int r; int r;
log_dbg("%s volume %s using token %d.", log_dbg(cd, "%s volume %s using token %d.",
name ? "Activating" : "Checking", name ?: "passphrase", token); name ? "Activating" : "Checking", name ?: "passphrase", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED))) if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED)))
return r; return r;
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd) ) if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd) )
return -EINVAL; return -EINVAL;
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name) if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
return -EINVAL; return -EINVAL;
skipping to change at line 4154 skipping to change at line 5012
return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, token, name, f lags, usrptr); return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, token, name, f lags, usrptr);
} }
int crypt_token_json_get(struct crypt_device *cd, int token, const char **json) int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
{ {
int r; int r;
if (!json) if (!json)
return -EINVAL; return -EINVAL;
log_dbg("Requesting JSON for token %d.", token); log_dbg(cd, "Requesting JSON for token %d.", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED))) if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
return r; return r;
return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token; return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token;
} }
int crypt_token_json_set(struct crypt_device *cd, int token, const char *json) int crypt_token_json_set(struct crypt_device *cd, int token, const char *json)
{ {
int r; int r;
log_dbg("Updating JSON for token %d.", token); log_dbg(cd, "Updating JSON for token %d.", token);
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_token_create(cd, &cd->u.luks2.hdr, token, json, 1); return LUKS2_token_create(cd, &cd->u.luks2.hdr, token, json, 1);
} }
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const ch ar **type) crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const ch ar **type)
{ {
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED)) if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED))
skipping to change at line 4193 skipping to change at line 5051
int token, int token,
struct crypt_token_params_luks2_keyring *params) struct crypt_token_params_luks2_keyring *params)
{ {
crypt_token_info token_info; crypt_token_info token_info;
const char *type; const char *type;
int r; int r;
if (!params) if (!params)
return -EINVAL; return -EINVAL;
log_dbg("Requesting LUKS2 keyring token %d.", token); log_dbg(cd, "Requesting LUKS2 keyring token %d.", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED))) if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
return r; return r;
token_info = LUKS2_token_status(cd, &cd->u.luks2.hdr, token, &type); token_info = LUKS2_token_status(cd, &cd->u.luks2.hdr, token, &type);
switch (token_info) { switch (token_info) {
case CRYPT_TOKEN_INVALID: case CRYPT_TOKEN_INVALID:
log_dbg("Token %d is invalid.", token); log_dbg(cd, "Token %d is invalid.", token);
return -EINVAL; return -EINVAL;
case CRYPT_TOKEN_INACTIVE: case CRYPT_TOKEN_INACTIVE:
log_dbg("Token %d is inactive.", token); log_dbg(cd, "Token %d is inactive.", token);
return -EINVAL; return -EINVAL;
case CRYPT_TOKEN_INTERNAL: case CRYPT_TOKEN_INTERNAL:
if (!strcmp(type, LUKS2_TOKEN_KEYRING)) if (!strcmp(type, LUKS2_TOKEN_KEYRING))
break; break;
/* Fall through */ /* Fall through */
case CRYPT_TOKEN_INTERNAL_UNKNOWN: case CRYPT_TOKEN_INTERNAL_UNKNOWN:
case CRYPT_TOKEN_EXTERNAL: case CRYPT_TOKEN_EXTERNAL:
case CRYPT_TOKEN_EXTERNAL_UNKNOWN: case CRYPT_TOKEN_EXTERNAL_UNKNOWN:
log_dbg("Token %d has unexpected type %s.", token, type); log_dbg(cd, "Token %d has unexpected type %s.", token, type);
return -EINVAL; return -EINVAL;
} }
return LUKS2_builtin_token_get(cd, &cd->u.luks2.hdr, token, LUKS2_TOKEN_K EYRING, params); return LUKS2_builtin_token_get(cd, &cd->u.luks2.hdr, token, LUKS2_TOKEN_K EYRING, params);
} }
int crypt_token_luks2_keyring_set(struct crypt_device *cd, int crypt_token_luks2_keyring_set(struct crypt_device *cd,
int token, int token,
const struct crypt_token_params_luks2_keyring *params) const struct crypt_token_params_luks2_keyring *params)
{ {
int r; int r;
if (!params) if (!params)
return -EINVAL; return -EINVAL;
log_dbg("Creating new LUKS2 keyring token (%d).", token); log_dbg(cd, "Creating new LUKS2 keyring token (%d).", token);
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_builtin_token_create(cd, &cd->u.luks2.hdr, token, LUKS2_TOKE N_KEYRING, params, 1); return LUKS2_builtin_token_create(cd, &cd->u.luks2.hdr, token, LUKS2_TOKE N_KEYRING, params, 1);
} }
int crypt_token_assign_keyslot(struct crypt_device *cd, int token, int keyslot) int crypt_token_assign_keyslot(struct crypt_device *cd, int token, int keyslot)
{ {
int r; int r;
skipping to change at line 4389 skipping to change at line 5247
uint32_t flags) uint32_t flags)
{ {
int digest, r; int digest, r;
struct luks2_keyslot_params params; struct luks2_keyslot_params params;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
if (!passphrase || ((flags & CRYPT_VOLUME_KEY_NO_SEGMENT) && if (!passphrase || ((flags & CRYPT_VOLUME_KEY_NO_SEGMENT) &&
(flags & CRYPT_VOLUME_KEY_SET))) (flags & CRYPT_VOLUME_KEY_SET)))
return -EINVAL; return -EINVAL;
log_dbg("Adding new keyslot %d with volume key %sassigned to a crypt segm ent.", log_dbg(cd, "Adding new keyslot %d with volume key %sassigned to a crypt segment.",
keyslot, flags & CRYPT_VOLUME_KEY_NO_SEGMENT ? "un" : ""); keyslot, flags & CRYPT_VOLUME_KEY_NO_SEGMENT ? "un" : "");
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
/* new volume key assignment */ /* new volume key assignment */
if ((flags & CRYPT_VOLUME_KEY_SET) && crypt_keyslot_status(cd, keyslot) > CRYPT_SLOT_INACTIVE) if ((flags & CRYPT_VOLUME_KEY_SET) && crypt_keyslot_status(cd, keyslot) > CRYPT_SLOT_INACTIVE)
return verify_and_update_segment_digest(cd, &cd->u.luks2.hdr, return verify_and_update_segment_digest(cd, &cd->u.luks2.hdr,
keyslot, volume_key, volume_key_size, passphrase, passphr ase_size); keyslot, volume_key, volume_key_size, passphrase, passphr ase_size);
skipping to change at line 4422 skipping to change at line 5280
if (!vk) if (!vk)
return -ENOMEM; return -ENOMEM;
/* if key matches volume key digest tear down new vk flag */ /* if key matches volume key digest tear down new vk flag */
digest = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAU LT_SEGMENT, vk); digest = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAU LT_SEGMENT, vk);
if (digest >= 0) if (digest >= 0)
flags &= ~CRYPT_VOLUME_KEY_SET; flags &= ~CRYPT_VOLUME_KEY_SET;
/* no segment flag or new vk flag requires new key digest */ /* no segment flag or new vk flag requires new key digest */
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) { if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET))
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk); digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, 0, &params
);
} else
r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, vk->keylen
gth, &params);
r = digest;
if (r < 0) { if (r < 0) {
log_err(cd, _("Failed to initialise default LUKS2 keyslot paramet ers.")); log_err(cd, _("Volume key does not match the volume."));
goto out; goto out;
} }
r = digest; r = LUKS2_keyslot_params_default(cd, &cd->u.luks2.hdr, &params);
if (r < 0) { if (r < 0) {
log_err(cd, _("Volume key does not match the volume.")); log_err(cd, _("Failed to initialise default LUKS2 keyslot paramet ers."));
goto out; goto out;
} }
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0); r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot, digest, 1, 0);
if (r < 0) { if (r < 0) {
log_err(cd, _("Failed to assign keyslot %d to digest."), keyslot) ; log_err(cd, _("Failed to assign keyslot %d to digest."), keyslot) ;
goto out; goto out;
} }
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot, r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, keyslot,
skipping to change at line 4484 skipping to change at line 5340
static int dmcrypt_keyring_bug(void) static int dmcrypt_keyring_bug(void)
{ {
uint64_t kversion; uint64_t kversion;
if (kernel_version(&kversion)) if (kernel_version(&kversion))
return 1; return 1;
return kversion < version(4,15,0,0); return kversion < version(4,15,0,0);
} }
int crypt_use_keyring_for_vk(const struct crypt_device *cd) int crypt_use_keyring_for_vk(struct crypt_device *cd)
{ {
uint32_t dmc_flags; uint32_t dmc_flags;
/* dm backend must be initialised */ /* dm backend must be initialised */
if (!cd || !isLUKS2(cd->type)) if (!cd || !isLUKS2(cd->type))
return 0; return 0;
if (!_vk_via_keyring || !kernel_keyring_support()) if (!_vk_via_keyring || !kernel_keyring_support())
return 0; return 0;
if (dm_flags(DM_CRYPT, &dmc_flags)) if (dm_flags(cd, DM_CRYPT, &dmc_flags))
return dmcrypt_keyring_bug() ? 0 : 1; return dmcrypt_keyring_bug() ? 0 : 1;
return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED); return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED);
} }
int crypt_volume_key_keyring(struct crypt_device *cd, int enable) int crypt_volume_key_keyring(struct crypt_device *cd, int enable)
{ {
_vk_via_keyring = enable ? 1 : 0; _vk_via_keyring = enable ? 1 : 0;
return 0; return 0;
} }
/* internal only */ /* internal only */
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk) int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
{ {
int r; int r;
if (!vk || !cd) if (!vk || !cd)
return -EINVAL; return -EINVAL;
if (!vk->key_description) { if (!vk->key_description) {
log_dbg("Invalid key description"); log_dbg(cd, "Invalid key description");
return -EINVAL; return -EINVAL;
} }
log_dbg("Loading key (%zu bytes) in thread keyring.", vk->keylength); log_dbg(cd, "Loading key (%zu bytes) in thread keyring.", vk->keylength);
r = keyring_add_key_in_thread_keyring(vk->key_description, vk->key, vk->k eylength); r = keyring_add_key_in_thread_keyring(vk->key_description, vk->key, vk->k eylength);
if (r) { if (r) {
log_dbg("keyring_add_key_in_thread_keyring failed (error %d)", r) ; log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)" , r);
log_err(cd, _("Failed to load key in kernel keyring.")); log_err(cd, _("Failed to load key in kernel keyring."));
} else } else
crypt_set_key_in_keyring(cd, 1); crypt_set_key_in_keyring(cd, 1);
return r; return r;
} }
/* internal only */ /* internal only */
int crypt_key_in_keyring(struct crypt_device *cd) int crypt_key_in_keyring(struct crypt_device *cd)
{ {
skipping to change at line 4555 skipping to change at line 5411
} }
/* internal only */ /* internal only */
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description ) void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description )
{ {
int r; int r;
if (!key_description) if (!key_description)
return; return;
log_dbg("Requesting keyring key for revoke and unlink."); log_dbg(cd, "Requesting keyring key for revoke and unlink.");
r = keyring_revoke_and_unlink_key(key_description); r = keyring_revoke_and_unlink_key(key_description);
if (r) if (r)
log_dbg("keyring_revoke_and_unlink failed (error %d)", r); log_dbg(cd, "keyring_revoke_and_unlink failed (error %d)", r);
crypt_set_key_in_keyring(cd, 0); crypt_set_key_in_keyring(cd, 0);
} }
int crypt_activate_by_keyring(struct crypt_device *cd, int crypt_activate_by_keyring(struct crypt_device *cd,
const char *name, const char *name,
const char *key_description, const char *key_description,
int keyslot, int keyslot,
uint32_t flags) uint32_t flags)
{ {
char *passphrase; char *passphrase;
size_t passphrase_size; size_t passphrase_size;
int r; int r;
if (!cd || !key_description) if (!cd || !key_description)
return -EINVAL; return -EINVAL;
log_dbg("%s volume %s [keyslot %d] using passphrase in keyring.", log_dbg(cd, "%s volume %s [keyslot %d] using passphrase in keyring.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot); name ? "Activating" : "Checking", name ?: "passphrase", keyslot);
if (!kernel_keyring_support()) { if (!kernel_keyring_support()) {
log_err(cd, _("Kernel keyring is not supported by the kernel.")); log_err(cd, _("Kernel keyring is not supported by the kernel."));
return -EINVAL; return -EINVAL;
} }
r = _activate_check_status(cd, name); r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0) if (r < 0)
return r; return r;
r = keyring_get_passphrase(key_description, &passphrase, &passphrase_size ); r = keyring_get_passphrase(key_description, &passphrase, &passphrase_size );
if (r < 0) { if (r < 0) {
log_err(cd, _("Failed to read passphrase from keyring (error %d). "), r); log_err(cd, _("Failed to read passphrase from keyring (error %d). "), r);
return -EINVAL; return -EINVAL;
} }
r = _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_siz e, flags); r = _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_siz e, flags);
 End of changes. 282 change blocks. 
463 lines changed or deleted 1385 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)