mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-07 08:50:05 +01:00
Add resilient LUKS2 reencryption library code.
This commit is contained in:
@@ -99,6 +99,8 @@ libcryptsetup_la_SOURCES = \
|
||||
lib/luks2/luks2_digest_pbkdf2.c \
|
||||
lib/luks2/luks2_keyslot.c \
|
||||
lib/luks2/luks2_keyslot_luks2.c \
|
||||
lib/luks2/luks2_keyslot_reenc.c \
|
||||
lib/luks2/luks2_reencrypt.c \
|
||||
lib/luks2/luks2_segment.c \
|
||||
lib/luks2/luks2_token_keyring.c \
|
||||
lib/luks2/luks2_token.c \
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "utils_keyring.h"
|
||||
#include "utils_io.h"
|
||||
#include "crypto_backend.h"
|
||||
#include "utils_storage_wrappers.h"
|
||||
|
||||
#include "libcryptsetup.h"
|
||||
|
||||
@@ -73,6 +74,7 @@
|
||||
} while (0)
|
||||
|
||||
struct crypt_device;
|
||||
struct luks2_reenc_context;
|
||||
|
||||
struct volume_key {
|
||||
int id;
|
||||
@@ -120,6 +122,7 @@ size_t device_block_size(struct crypt_device *cd, struct device *device);
|
||||
int device_read_ahead(struct device *device, uint32_t *read_ahead);
|
||||
int device_size(struct device *device, uint64_t *size);
|
||||
int device_open(struct crypt_device *cd, struct device *device, int flags);
|
||||
int device_open_excl(struct crypt_device *cd, struct device *device, int flags);
|
||||
void device_disable_direct_io(struct device *device);
|
||||
int device_is_identical(struct device *device1, struct device *device2);
|
||||
int device_is_rotational(struct device *device);
|
||||
@@ -207,6 +210,11 @@ int PLAIN_activate(struct crypt_device *cd,
|
||||
uint32_t flags);
|
||||
|
||||
void *crypt_get_hdr(struct crypt_device *cd, const char *type);
|
||||
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd);
|
||||
|
||||
int onlyLUKS2(struct crypt_device *cd);
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask);
|
||||
|
||||
int crypt_wipe_device(struct crypt_device *cd,
|
||||
struct device *device,
|
||||
|
||||
@@ -1108,6 +1108,8 @@ uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd,
|
||||
*/
|
||||
/** Unfinished offline reencryption */
|
||||
#define CRYPT_REQUIREMENT_OFFLINE_REENCRYPT (1 << 0)
|
||||
/** Online reencryption in-progress */
|
||||
#define CRYPT_REQUIREMENT_ONLINE_REENCRYPT (1 << 1)
|
||||
/** unknown requirement in header (output only) */
|
||||
#define CRYPT_REQUIREMENT_UNKNOWN (1 << 31)
|
||||
|
||||
@@ -2103,6 +2105,134 @@ int crypt_activate_by_token(struct crypt_device *cd,
|
||||
uint32_t flags);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup crypt-reencryption LUKS2 volume reencryption support
|
||||
*
|
||||
* Set of functions to handling LUKS2 volume reencryption
|
||||
*
|
||||
* @addtogroup crypt-reencryption
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Initialize reencryption metadata but do not run reencryption yet. */
|
||||
#define CRYPT_REENCRYPT_INITIALIZE_ONLY (1 << 0)
|
||||
/** Move the first segment; used only with data shift. */
|
||||
#define CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT (1 << 1)
|
||||
|
||||
/**
|
||||
* Reencryption direction
|
||||
*/
|
||||
typedef enum {
|
||||
CRYPT_REENCRYPT_FORWARD = 0, /**< forward direction */
|
||||
CRYPT_REENCRYPT_BACKWARD /**< backward direction */
|
||||
} crypt_reencrypt_direction_info;
|
||||
|
||||
/**
|
||||
* LUKS2 reencryption options.
|
||||
*/
|
||||
struct crypt_params_reencrypt {
|
||||
const char *mode; /**< Mode as "encrypt" / "reencrypt" / "decrypt", immutable after first init. */
|
||||
crypt_reencrypt_direction_info direction; /**< Reencryption direction, immutable after first init. */
|
||||
const char *resilience; /**< Resilience mode: "none", "checksum", "journal" or "shift" (only "shift" is immutable after init) */
|
||||
const char *hash; /**< Used hash for "checksum" resilience type, ignored otherwise. */
|
||||
uint64_t data_shift; /**< Used in "shift" mode, must be non-zero, immutable after first init. */
|
||||
uint64_t max_hotzone_size; /**< Hotzone size for "none" mode; maximum hotzone size for "checksum" mode. */
|
||||
const struct crypt_params_luks2 *luks2; /**< LUKS2 parameters for the final reencryption volume.*/
|
||||
uint32_t flags; /**< Reencryption flags. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize reencryption metadata using passphrase.
|
||||
*
|
||||
* This function initializes on-disk metadata to include all reencryption segments,
|
||||
* according to the provided options.
|
||||
* If metadata already contains ongoing reencryption metadata, it loads these parameters
|
||||
* (in this situation all parameters except @e name and @e passphrase can be omitted).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of active device or @e NULL for offline reencryption
|
||||
* @param passphrase passphrase used to unlock volume key
|
||||
* @param passphrase_size size of @e passphrase (binary data)
|
||||
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
|
||||
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
|
||||
* @param cipher cipher specification (e.g. "aes")
|
||||
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
|
||||
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
|
||||
*
|
||||
* @return reencryption key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* Initialize reencryption metadata using passphrase in keyring.
|
||||
*
|
||||
* This function initializes on-disk metadata to include all reencryption segments,
|
||||
* according to the provided options.
|
||||
* If metadata already contains ongoing reencryption metadata, it loads these parameters
|
||||
* (in this situation all parameters except @e name and @e key_description can be omitted).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of active device or @e NULL for offline reencryption
|
||||
* @param key_description passphrase (key) identification in keyring
|
||||
* @param keyslot_old keyslot to unlock existing device or CRYPT_ANY_SLOT
|
||||
* @param keyslot_new existing (unbound) reencryption keyslot; must be set except for decryption
|
||||
* @param cipher cipher specification (e.g. "aes")
|
||||
* @param cipher_mode cipher mode and IV (e.g. "xts-plain64")
|
||||
* @param params reencryption parameters @link crypt_params_reencrypt @endlink.
|
||||
*
|
||||
* @return reencryption key slot number or negative errno otherwise.
|
||||
*/
|
||||
int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_description,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *cipher,
|
||||
const char *cipher_mode,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* Run data reencryption.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param progress is a callback funtion reporting device \b size,
|
||||
* current \b offset of reencryption and provided \b usrptr identification
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*/
|
||||
int crypt_reencrypt(struct crypt_device *cd,
|
||||
int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
|
||||
|
||||
/**
|
||||
* Reencryption status info
|
||||
*/
|
||||
typedef enum {
|
||||
CRYPT_REENCRYPT_NONE = 0, /**< No reencryption in progress */
|
||||
CRYPT_REENCRYPT_CLEAN, /**< Ongoing reencryption in a clean state. */
|
||||
CRYPT_REENCRYPT_CRASH, /**< Aborted reencryption that need internal recovery. */
|
||||
CRYPT_REENCRYPT_INVALID /**< Invalid state. */
|
||||
} crypt_reencrypt_info;
|
||||
|
||||
/**
|
||||
* LUKS2 reencryption status.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param params reecryption parameters
|
||||
*
|
||||
* @return reencryption status info and parameters.
|
||||
*/
|
||||
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
|
||||
struct crypt_params_reencrypt *params);
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,6 +113,11 @@ CRYPTSETUP_2.0 {
|
||||
crypt_keyfile_device_read;
|
||||
|
||||
crypt_wipe;
|
||||
|
||||
crypt_reencrypt_init_by_passphrase;
|
||||
crypt_reencrypt_init_by_keyring;
|
||||
crypt_reencrypt;
|
||||
crypt_reencrypt_status;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
@@ -48,9 +48,13 @@
|
||||
|
||||
#define CRYPT_ANY_SEGMENT -1
|
||||
#define CRYPT_DEFAULT_SEGMENT -2
|
||||
#define CRYPT_ONE_SEGMENT -3
|
||||
|
||||
#define CRYPT_ANY_DIGEST -1
|
||||
|
||||
/* 20 MiBs */
|
||||
#define LUKS2_DEFAULT_REENCRYPTION_LENGTH 0x1400000
|
||||
|
||||
/*
|
||||
* LUKS2 header on-disk.
|
||||
*
|
||||
@@ -118,6 +122,80 @@ struct luks2_keyslot_params {
|
||||
} area;
|
||||
};
|
||||
|
||||
struct reenc_protection {
|
||||
enum { REENC_PROTECTION_NOOP = 0, /* none should be 0 always */
|
||||
REENC_PROTECTION_CHECKSUM,
|
||||
REENC_PROTECTION_JOURNAL,
|
||||
REENC_PROTECTION_DATASHIFT } type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
} none;
|
||||
struct {
|
||||
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
|
||||
struct crypt_hash *ch;
|
||||
size_t hash_size;
|
||||
/* buffer for checksums */
|
||||
void *checksums;
|
||||
size_t checksums_len;
|
||||
} csum;
|
||||
struct {
|
||||
} ds;
|
||||
} p;
|
||||
};
|
||||
|
||||
struct luks2_reenc_context {
|
||||
/* reencryption window attributes */
|
||||
uint64_t offset;
|
||||
uint64_t progress;
|
||||
uint64_t length;
|
||||
uint64_t data_shift;
|
||||
size_t alignment;
|
||||
uint64_t device_size;
|
||||
bool online;
|
||||
crypt_reencrypt_direction_info direction;
|
||||
|
||||
enum { REENCRYPT = 0, ENCRYPT, DECRYPT } type;
|
||||
|
||||
char *device_name;
|
||||
char *hotzone_name;
|
||||
char *overlay_name;
|
||||
|
||||
/* reencryption window persistence attributes */
|
||||
struct reenc_protection rp;
|
||||
|
||||
int reenc_keyslot;
|
||||
|
||||
/* already running reencryption */
|
||||
json_object *jobj_segs_pre;
|
||||
json_object *jobj_segs_after;
|
||||
|
||||
/* backup segments */
|
||||
json_object *jobj_segment_new;
|
||||
int digest_new;
|
||||
json_object *jobj_segment_old;
|
||||
int digest_old;
|
||||
json_object *jobj_segment_moved;
|
||||
|
||||
struct volume_key *vks;
|
||||
|
||||
void *reenc_buffer;
|
||||
ssize_t read;
|
||||
|
||||
struct crypt_storage_wrapper *cw1;
|
||||
struct crypt_storage_wrapper *cw2;
|
||||
|
||||
uint32_t wflags1;
|
||||
uint32_t wflags2;
|
||||
|
||||
struct crypt_lock_handle *reenc_lock;
|
||||
};
|
||||
|
||||
int LUKS2_reenc_load_segments(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_reenc_context *rh);
|
||||
|
||||
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr);
|
||||
/*
|
||||
* Supportable header sizes (hdr_disk + JSON area)
|
||||
* Also used as offset for the 2nd header.
|
||||
@@ -179,6 +257,13 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
size_t password_len,
|
||||
struct volume_key **vk);
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks);
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -187,6 +272,20 @@ int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
const struct volume_key *vk,
|
||||
const struct luks2_keyslot_params *params);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_keyslot_wipe(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -274,6 +373,8 @@ uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise);
|
||||
const char *json_segment_get_cipher(json_object *jobj_segment);
|
||||
int json_segment_get_sector_size(json_object *jobj_segment);
|
||||
json_object *json_segment_get_flags(json_object *jobj_segment);
|
||||
bool json_segment_is_backup(json_object *jobj_segment);
|
||||
bool json_segment_is_reencrypt(json_object *jobj_segment);
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment);
|
||||
int json_segments_count(json_object *jobj_segments);
|
||||
json_object *json_segments_get_segment_by_flag(json_object *jobj_segments, const char *flag);
|
||||
@@ -293,8 +394,6 @@ json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag);
|
||||
|
||||
int LUKS2_segment_ignore(json_object *jobj_segment);
|
||||
|
||||
json_object *LUKS2_get_ignored_segments(struct luks2_hdr *hdr);
|
||||
|
||||
int LUKS2_segments_set(struct crypt_device *cd,
|
||||
@@ -324,22 +423,11 @@ int LUKS2_last_segment_by_type(struct luks2_hdr *hdr,
|
||||
|
||||
int LUKS2_get_default_segment(struct luks2_hdr *hdr);
|
||||
|
||||
json_object *LUKS2_reencrypt_segment_new(struct luks2_hdr *hdr);
|
||||
json_object *LUKS2_reencrypt_segment_old(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_segment_cipher_new(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_segment_cipher_old(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_get_sector_size_new(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_get_sector_size_old(struct luks2_hdr *hdr);
|
||||
uint64_t LUKS2_reencrypt_get_data_offset_new(struct luks2_hdr *hdr);
|
||||
uint64_t LUKS2_reencrypt_get_data_offset_old(struct luks2_hdr *hdr);
|
||||
uint64_t LUKS2_reencrypt_get_data_offset_moved(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_digest_new(struct luks2_hdr *hdr);
|
||||
int LUKS2_reencrypt_digest_old(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_protection_type(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_protection_hash(struct luks2_hdr *hdr);
|
||||
uint32_t LUKS2_reencrypt_protection_sector_size(struct luks2_hdr *hdr);
|
||||
int64_t LUKS2_reencrypt_data_dev_diff(struct luks2_hdr *hdr);
|
||||
int64_t LUKS2_reencrypt_data_shift(struct luks2_hdr *hdr);
|
||||
uint64_t LUKS2_reencrypt_data_shift(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_reencrypt_mode(struct luks2_hdr *hdr);
|
||||
|
||||
/*
|
||||
@@ -351,6 +439,11 @@ int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
|
||||
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
|
||||
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const struct volume_key *vk);
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
@@ -396,6 +489,24 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
struct volume_key *vk,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_activate_multi(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint32_t flags);
|
||||
|
||||
struct crypt_dm_active_device;
|
||||
|
||||
int LUKS2_deactivate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct luks2_hdr *hdr,
|
||||
struct crypt_dm_active_device *dmd,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_reload(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint32_t flags);
|
||||
|
||||
int LUKS2_keyslot_luks2_format(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -424,6 +535,7 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr);
|
||||
|
||||
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr);
|
||||
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size);
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr);
|
||||
const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment);
|
||||
const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment);
|
||||
@@ -435,12 +547,17 @@ const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t
|
||||
int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr);
|
||||
int LUKS2_keyslot_active_count(struct luks2_hdr *hdr, int segment);
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment);
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type);
|
||||
int LUKS2_find_keyslot_for_segment(struct luks2_hdr *hdr, int segment, const char *type);
|
||||
crypt_keyslot_info LUKS2_keyslot_info(struct luks2_hdr *hdr, int keyslot);
|
||||
int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
uint64_t *offset,
|
||||
uint64_t *length);
|
||||
int LUKS2_keyslot_pbkdf(struct luks2_hdr *hdr, int keyslot, struct crypt_pbkdf_type *pbkdf);
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset);
|
||||
|
||||
/*
|
||||
* Permanent activation flags stored in header
|
||||
@@ -456,10 +573,13 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
|
||||
|
||||
char *LUKS2_key_description_by_digest(struct crypt_device *cd, int digest);
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
|
||||
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest);
|
||||
|
||||
struct luks_phdr;
|
||||
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
|
||||
@@ -469,4 +589,37 @@ int LUKS2_luks2_to_luks1(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr2,
|
||||
struct luks_phdr *hdr1);
|
||||
|
||||
/*
|
||||
* LUKS2 reencryption
|
||||
*/
|
||||
int LUKS2_verify_and_upload_keys(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest_old,
|
||||
int digest_new,
|
||||
struct volume_key *vks);
|
||||
|
||||
int LUKS2_reenc_load(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t device_size,
|
||||
const struct crypt_params_reencrypt *params,
|
||||
struct luks2_reenc_context **rh);
|
||||
|
||||
int LUKS2_reenc_update_segments(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_reenc_context *rh);
|
||||
|
||||
int LUKS2_reenc_recover(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct luks2_reenc_context *rh,
|
||||
struct volume_key *vks);
|
||||
|
||||
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_context *rh);
|
||||
|
||||
int reenc_erase_backup_segments(struct crypt_device *cd, struct luks2_hdr *hdr);
|
||||
|
||||
int crypt_reencrypt_lock(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock);
|
||||
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *reencrypt_lock);
|
||||
|
||||
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t *device_size, bool activation);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,7 +110,8 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int _digest_verify(struct crypt_device *cd,
|
||||
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int digest,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
@@ -122,10 +123,12 @@ static int _digest_verify(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
|
||||
r = h->verify(cd, digest, vk->key, vk->keylength);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
return digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
@@ -133,15 +136,15 @@ int LUKS2_digest_verify(struct crypt_device *cd,
|
||||
const struct volume_key *vk,
|
||||
int keyslot)
|
||||
{
|
||||
int digest, r;
|
||||
int digest;
|
||||
|
||||
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
r = _digest_verify(cd, digest, vk);
|
||||
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
|
||||
|
||||
return r < 0 ? r : digest;
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, digest, vk);
|
||||
}
|
||||
|
||||
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
@@ -154,39 +157,27 @@ int LUKS2_digest_dump(struct crypt_device *cd, int digest)
|
||||
return h->dump(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int digest, r;
|
||||
|
||||
digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
if (digest < 0)
|
||||
return digest;
|
||||
|
||||
log_dbg(cd, "Verifying key digest %d.", digest);
|
||||
|
||||
r = _digest_verify(cd, digest, vk);
|
||||
|
||||
return r < 0 ? r : digest;
|
||||
}
|
||||
|
||||
int LUKS2_digest_any_matching(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
int digest;
|
||||
|
||||
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++) {
|
||||
if (_digest_verify(cd, digest, vk) < 0)
|
||||
continue;
|
||||
return digest;
|
||||
}
|
||||
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++)
|
||||
if (LUKS2_digest_verify_by_digest(cd, hdr, digest, vk) == digest)
|
||||
return digest;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int segment,
|
||||
const struct volume_key *vk)
|
||||
{
|
||||
return LUKS2_digest_verify_by_digest(cd, hdr, LUKS2_digest_by_segment(hdr, segment), vk);
|
||||
}
|
||||
|
||||
/* FIXME: segment can have more digests */
|
||||
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
|
||||
{
|
||||
@@ -424,6 +415,11 @@ static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
return desc;
|
||||
}
|
||||
|
||||
char *LUKS2_key_description_by_digest(struct crypt_device *cd, int digest)
|
||||
{
|
||||
return get_key_description_by_digest(cd, digest);
|
||||
}
|
||||
|
||||
int LUKS2_key_description_by_segment(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
|
||||
{
|
||||
@@ -448,3 +444,17 @@ int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr, struct volume_key *vk, int digest)
|
||||
{
|
||||
char *desc = get_key_description_by_digest(cd, digest);
|
||||
int r;
|
||||
|
||||
r = crypt_volume_key_set_description(vk, desc);
|
||||
if (!r)
|
||||
r = crypt_volume_key_load_in_keyring(cd, vk);
|
||||
|
||||
free(desc);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -62,10 +62,8 @@ void hexprint_base64(struct crypt_device *cd, json_object *jobj,
|
||||
json_object *parse_json_len(struct crypt_device *cd, const char *json_area,
|
||||
uint64_t max_length, int *json_len);
|
||||
uint64_t json_object_get_uint64(json_object *jobj);
|
||||
int64_t json_object_get_int64_ex(json_object *jobj);
|
||||
uint32_t json_object_get_uint32(json_object *jobj);
|
||||
json_object *json_object_new_uint64(uint64_t value);
|
||||
json_object *json_object_new_int64_ex(int64_t value);
|
||||
|
||||
int json_object_object_add_by_uint(json_object *jobj, unsigned key, json_object *jobj_val);
|
||||
void json_object_object_del_by_uint(json_object *jobj, unsigned key);
|
||||
@@ -78,6 +76,7 @@ void JSON_DBG(struct crypt_device *cd, json_object *jobj, const char *desc);
|
||||
*/
|
||||
|
||||
/* validation helper */
|
||||
json_bool validate_json_uint32(json_object *jobj);
|
||||
json_object *json_contains(struct crypt_device *cd, json_object *jobj, const char *name,
|
||||
const char *section, const char *key, json_type type);
|
||||
|
||||
@@ -146,6 +145,12 @@ typedef struct {
|
||||
keyslot_repair_func repair;
|
||||
} keyslot_handler;
|
||||
|
||||
/* can not fit prototype alloc function */
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params);
|
||||
|
||||
/**
|
||||
* LUKS2 digest handlers (EXPERIMENTAL)
|
||||
*/
|
||||
@@ -186,4 +191,8 @@ int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
int LUKS2_find_area_max_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
uint64_t *area_offset, uint64_t *area_length);
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode);
|
||||
#endif
|
||||
|
||||
@@ -370,3 +370,30 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
|
||||
return crypt_wipe_device(cd, crypt_metadata_device(cd), CRYPT_WIPE_RANDOM,
|
||||
offset, length, wipe_block, NULL, NULL);
|
||||
}
|
||||
|
||||
/* FIXME: what if user wanted to keep original keyslots size? */
|
||||
int LUKS2_set_keyslots_size(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
uint64_t data_offset)
|
||||
{
|
||||
json_object *jobj_config;
|
||||
uint64_t keyslots_size;
|
||||
|
||||
if (data_offset < get_min_offset(hdr))
|
||||
return 1;
|
||||
|
||||
keyslots_size = data_offset - get_min_offset(hdr);
|
||||
|
||||
/* keep keyslots_size reasonable for custom data alignments */
|
||||
if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
|
||||
keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
|
||||
|
||||
/* keyslots size has to be 4 KiB aligned */
|
||||
keyslots_size -= (keyslots_size % 4096);
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
|
||||
return 1;
|
||||
|
||||
json_object_object_add(jobj_config, "keyslots_size", json_object_new_uint64(keyslots_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,10 @@ int LUKS2_segments_count(struct luks2_hdr *hdr)
|
||||
|
||||
int LUKS2_get_default_segment(struct luks2_hdr *hdr)
|
||||
{
|
||||
int s = LUKS2_get_segment_id_by_flag(hdr, "backup-final");
|
||||
if (s >= 0)
|
||||
return s;
|
||||
|
||||
if (LUKS2_segments_count(hdr) == 1)
|
||||
return 0;
|
||||
|
||||
@@ -212,25 +216,6 @@ uint32_t json_object_get_uint32(json_object *jobj)
|
||||
return json_object_get_int64(jobj);
|
||||
}
|
||||
|
||||
/* jobj has to be json_type_string and numbered */
|
||||
static json_bool json_str_to_int64(json_object *jobj, int64_t *value)
|
||||
{
|
||||
char *endptr;
|
||||
long long int tmp;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtoll(json_object_get_string(jobj), &endptr, 10);
|
||||
if (*endptr || errno) {
|
||||
log_dbg(NULL, "Failed to parse int64_t type from string %s.",
|
||||
json_object_get_string(jobj));
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*value = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* jobj has to be json_type_string and numbered */
|
||||
static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
|
||||
{
|
||||
@@ -248,13 +233,6 @@ static json_bool json_str_to_uint64(json_object *jobj, uint64_t *value)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int64_t json_object_get_int64_ex(json_object *jobj)
|
||||
{
|
||||
int64_t r;
|
||||
json_str_to_int64(jobj, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t json_object_get_uint64(json_object *jobj)
|
||||
{
|
||||
uint64_t r;
|
||||
@@ -277,21 +255,6 @@ json_object *json_object_new_uint64(uint64_t value)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
json_object *json_object_new_int64_ex(int64_t value)
|
||||
{
|
||||
/* 18446744073709551615 */
|
||||
char num[21];
|
||||
int r;
|
||||
json_object *jobj;
|
||||
|
||||
r = snprintf(num, sizeof(num), "%" PRIi64, value);
|
||||
if (r < 0 || (size_t)r >= sizeof(num))
|
||||
return NULL;
|
||||
|
||||
jobj = json_object_new_string(num);
|
||||
return jobj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate helpers
|
||||
*/
|
||||
@@ -322,7 +285,7 @@ json_object *json_contains(struct crypt_device *cd, json_object *jobj, const cha
|
||||
return sobj;
|
||||
}
|
||||
|
||||
static json_bool validate_json_uint32(json_object *jobj)
|
||||
json_bool validate_json_uint32(json_object *jobj)
|
||||
{
|
||||
int64_t tmp;
|
||||
|
||||
@@ -592,18 +555,48 @@ static int hdr_validate_crypt_segment(struct crypt_device *cd,
|
||||
return !segment_has_digest(key, jobj_digests);
|
||||
}
|
||||
|
||||
static bool validate_segment_intervals(struct crypt_device *cd,
|
||||
int length, const struct interval *ix)
|
||||
{
|
||||
int j, i = 0;
|
||||
|
||||
while (i < length) {
|
||||
if (ix[i].length == UINT64_MAX && (i != (length - 1))) {
|
||||
log_dbg(cd, "Only last regular segment is allowed to have 'dynamic' size.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (j = 0; j < length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
if ((ix[i].offset >= ix[j].offset) && (ix[j].length == UINT64_MAX || (ix[i].offset < (ix[j].offset + ix[j].length)))) {
|
||||
log_dbg(cd, "Overlapping segments [%" PRIu64 ",%" PRIu64 "]%s and [%" PRIu64 ",%" PRIu64 "]%s.",
|
||||
ix[i].offset, ix[i].offset + ix[i].length, ix[i].length == UINT64_MAX ? "(dynamic)" : "",
|
||||
ix[j].offset, ix[j].offset + ix[j].length, ix[j].length == UINT64_MAX ? "(dynamic)" : "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
{
|
||||
json_object *jobj, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags;
|
||||
int i;
|
||||
json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj;
|
||||
struct interval *intervals;
|
||||
uint64_t offset, size;
|
||||
int i, r, count, first_backup = -1;
|
||||
|
||||
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj)) {
|
||||
if (!json_object_object_get_ex(hdr_jobj, "segments", &jobj_segments)) {
|
||||
log_dbg(cd, "Missing segments section.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (json_object_object_length(jobj) < 1) {
|
||||
count = json_object_object_length(jobj_segments);
|
||||
if (count < 1) {
|
||||
log_dbg(cd, "Empty segments section.");
|
||||
return 1;
|
||||
}
|
||||
@@ -612,7 +605,7 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
if (!json_object_object_get_ex(hdr_jobj, "digests", &jobj_digests))
|
||||
return 1;
|
||||
|
||||
json_object_object_foreach(jobj, key, val) {
|
||||
json_object_object_foreach(jobj_segments, key, val) {
|
||||
if (!numbered(cd, "Segment", key))
|
||||
return 1;
|
||||
|
||||
@@ -653,12 +646,61 @@ static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = atoi(key);
|
||||
if (json_segment_is_backup(val)) {
|
||||
if (first_backup < 0 || i < first_backup)
|
||||
first_backup = i;
|
||||
} else {
|
||||
if ((first_backup >= 0) && i >= first_backup) {
|
||||
log_dbg(cd, "Regular segment at %d is behind backup segment at %d", i, first_backup);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* crypt */
|
||||
if (!strcmp(json_object_get_string(jobj_type), "crypt") &&
|
||||
hdr_validate_crypt_segment(cd, val, key, jobj_digests, offset, size))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (first_backup == 0) {
|
||||
log_dbg(cd, "No regular segment.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (first_backup < 0)
|
||||
first_backup = count;
|
||||
|
||||
intervals = malloc(first_backup * sizeof(*intervals));
|
||||
if (!intervals) {
|
||||
log_dbg(cd, "Not enough memory.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < first_backup; i++) {
|
||||
jobj = json_segments_get_segment(jobj_segments, i);
|
||||
if (!jobj) {
|
||||
log_dbg(cd, "Gap at key %d in segments object.", i);
|
||||
free(intervals);
|
||||
return 1;
|
||||
}
|
||||
intervals[i].offset = json_segment_get_offset(jobj, 0);
|
||||
intervals[i].length = json_segment_get_size(jobj, 0) ?: UINT64_MAX;
|
||||
}
|
||||
|
||||
r = !validate_segment_intervals(cd, first_backup, intervals);
|
||||
free(intervals);
|
||||
|
||||
if (r)
|
||||
return 1;
|
||||
|
||||
for (; i < count; i++) {
|
||||
if (!json_segments_get_segment(jobj_segments, i)) {
|
||||
log_dbg(cd, "Gap at key %d in segments object.", i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1064,6 +1106,11 @@ static int reqs_reencrypt(uint32_t reqs)
|
||||
return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
static int reqs_reencrypt_online(uint32_t reqs)
|
||||
{
|
||||
return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
|
||||
}
|
||||
|
||||
int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
const char *backup_file)
|
||||
{
|
||||
@@ -1098,7 +1145,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
}
|
||||
|
||||
/* do not allow header restore from backup with unmet requirements */
|
||||
if (LUKS2_unmet_requirements(cd, &hdr_file, 0, 1)) {
|
||||
if (LUKS2_unmet_requirements(cd, &hdr_file, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1)) {
|
||||
log_err(cd, _("Forbidden LUKS2 requirements detected in backup %s."),
|
||||
backup_file);
|
||||
r = -ETXTBSY;
|
||||
@@ -1309,6 +1356,7 @@ static const struct {
|
||||
const char *description;
|
||||
} requirements_flags[] = {
|
||||
{ CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" },
|
||||
{ CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
@@ -1502,7 +1550,7 @@ static void hdr_dump_keyslots(struct crypt_device *cd, json_object *hdr_jobj)
|
||||
json_object_object_get_ex(val, "type", &jobj2);
|
||||
tmps = json_object_get_string(jobj2);
|
||||
|
||||
r = LUKS2_keyslot_for_segment(crypt_get_hdr(cd, CRYPT_LUKS2), j, CRYPT_DEFAULT_SEGMENT);
|
||||
r = LUKS2_keyslot_for_segment(crypt_get_hdr(cd, CRYPT_LUKS2), j, CRYPT_ONE_SEGMENT);
|
||||
log_std(cd, " %s: %s%s\n", slot, tmps, r == -ENOENT ? " (unbound)" : "");
|
||||
|
||||
if (json_object_object_get_ex(val, "key_size", &jobj2))
|
||||
@@ -1659,8 +1707,56 @@ int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size)
|
||||
{
|
||||
json_object *jobj_segments, *jobj_size;
|
||||
uint64_t tmp = 0;
|
||||
int sector_size;
|
||||
|
||||
if (!size || !json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, val) {
|
||||
UNUSED(key);
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(val, "size", &jobj_size);
|
||||
if (!strcmp(json_object_get_string(jobj_size), "dynamic")) {
|
||||
sector_size = json_segment_get_sector_size(val);
|
||||
/* last dynamic segment must have at least one sector in size */
|
||||
if (tmp)
|
||||
*size = tmp + (sector_size > 0 ? sector_size : SECTOR_SIZE);
|
||||
else
|
||||
*size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp += json_object_get_uint64(jobj_size);
|
||||
}
|
||||
|
||||
/* impossible, segments with size set to 0 are illegal */
|
||||
if (!tmp)
|
||||
return -EINVAL;
|
||||
|
||||
*size = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_get_data_offset(struct luks2_hdr *hdr)
|
||||
{
|
||||
uint64_t new = 0, old = 0;
|
||||
json_object *jobj;
|
||||
|
||||
jobj = LUKS2_get_segment_by_flag(hdr, "backup-final");
|
||||
if (jobj) {
|
||||
new = json_segment_get_offset(jobj, 1);
|
||||
jobj = LUKS2_get_segment_by_flag(hdr, "backup-previous");
|
||||
if (jobj)
|
||||
old = json_segment_get_offset(jobj, 1);
|
||||
return new > old ? new : old;
|
||||
}
|
||||
|
||||
return json_segments_get_minimal_offset(LUKS2_get_segments_jobj(hdr), 1);
|
||||
}
|
||||
|
||||
@@ -1682,6 +1778,26 @@ const char *LUKS2_get_cipher(struct luks2_hdr *hdr, int segment)
|
||||
return json_segment_get_cipher(jobj_segment) ?: "null";
|
||||
}
|
||||
|
||||
crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr)
|
||||
{
|
||||
uint32_t reqs;
|
||||
|
||||
/*
|
||||
* Any unknown requirement or offline reencryption should abort
|
||||
* anything related to online-reencryption handling
|
||||
*/
|
||||
if (LUKS2_config_get_requirements(NULL, hdr, &reqs))
|
||||
return CRYPT_REENCRYPT_INVALID;
|
||||
|
||||
if (!reqs_reencrypt_online(reqs))
|
||||
return CRYPT_REENCRYPT_NONE;
|
||||
|
||||
if (json_segments_segment_in_reencrypt(LUKS2_get_segments_jobj(hdr)) < 0)
|
||||
return CRYPT_REENCRYPT_CLEAN;
|
||||
|
||||
return CRYPT_REENCRYPT_CRASH;
|
||||
}
|
||||
|
||||
const char *LUKS2_get_keyslot_cipher(struct luks2_hdr *hdr, int keyslot, size_t *key_size)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj1;
|
||||
@@ -1726,6 +1842,7 @@ const char *LUKS2_get_integrity(struct luks2_hdr *hdr, int segment)
|
||||
}
|
||||
|
||||
/* FIXME: this only ensures that once we have journal encryption, it is not ignored. */
|
||||
/* implement segment count and type restrictions (crypt and only single crypt) */
|
||||
static int LUKS2_integrity_compatible(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj1, *jobj2, *jobj3, *jobj4;
|
||||
@@ -1813,17 +1930,189 @@ int LUKS2_get_volume_key_size(struct luks2_hdr *hdr, int segment)
|
||||
|
||||
int LUKS2_get_sector_size(struct luks2_hdr *hdr)
|
||||
{
|
||||
json_object *jobj1, *jobj_segment;
|
||||
json_object *jobj_segment;
|
||||
|
||||
jobj_segment = LUKS2_get_segment_jobj(hdr, CRYPT_DEFAULT_SEGMENT);
|
||||
if (!jobj_segment)
|
||||
return SECTOR_SIZE;
|
||||
|
||||
json_object_object_get_ex(jobj_segment, "sector_size", &jobj1);
|
||||
if (!jobj1)
|
||||
return SECTOR_SIZE;
|
||||
return json_segment_get_sector_size(jobj_segment) ?: SECTOR_SIZE;
|
||||
}
|
||||
|
||||
return json_object_get_int(jobj1);
|
||||
static int _prepare_multi_dmd(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
struct volume_key *vks,
|
||||
json_object *jobj_segments,
|
||||
struct crypt_dm_active_device *dmd)
|
||||
{
|
||||
struct volume_key *vk;
|
||||
json_object *jobj;
|
||||
enum devcheck device_check;
|
||||
int r;
|
||||
unsigned s = 0;
|
||||
uint64_t data_offset, segment_size, segment_offset, segment_start = 0;
|
||||
struct dm_target *t = &dmd->segment;
|
||||
|
||||
if (dmd->flags & CRYPT_ACTIVATE_SHARED)
|
||||
device_check = DEV_OK;
|
||||
else
|
||||
device_check = DEV_EXCL;
|
||||
|
||||
/* FIXME: replace == 0 with < LUKS2_header_size() */
|
||||
data_offset = json_segments_get_minimal_offset(jobj_segments, 1);
|
||||
if (data_offset == 0 &&
|
||||
crypt_data_device(cd) == crypt_metadata_device(cd)) {
|
||||
log_dbg(cd, "Internal error. Wrong data offset");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = device_block_adjust(cd, crypt_data_device(cd), device_check,
|
||||
data_offset, &dmd->size, &dmd->flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = -EINVAL;
|
||||
|
||||
while (t) {
|
||||
jobj = json_segments_get_segment(jobj_segments, s);
|
||||
if (!jobj) {
|
||||
log_dbg(cd, "Internal error. Segment %u is null.", s);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
segment_offset = json_segment_get_offset(jobj, 1);
|
||||
segment_size = json_segment_get_size(jobj, 1);
|
||||
/* 'dynamic' length allowed in last segment only */
|
||||
if (!segment_size && !t->next)
|
||||
segment_size = dmd->size - segment_start;
|
||||
if (!segment_size) {
|
||||
log_dbg(cd, "Internal error. Wrong segment size %u", s);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(json_segment_type(jobj), "crypt")) {
|
||||
vk = crypt_volume_key_by_id(vks, LUKS2_digest_by_segment(hdr, s));
|
||||
if (!vk) {
|
||||
log_err(cd, _("Missing key for dm-crypt segment %u"), s);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = dm_crypt_target_set(t, segment_start, segment_size,
|
||||
crypt_data_device(cd), vk,
|
||||
json_segment_get_cipher(jobj),
|
||||
json_segment_get_iv_offset(jobj),
|
||||
segment_offset, "none", 0,
|
||||
json_segment_get_sector_size(jobj));
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to set dm-crypt segment."));
|
||||
return r;
|
||||
}
|
||||
} else if (!strcmp(json_segment_type(jobj), "linear")) {
|
||||
r = dm_linear_target_set(t, segment_start, segment_size, crypt_data_device(cd), segment_offset);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to set dm-linear segment."));
|
||||
return r;
|
||||
}
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
segment_start += segment_size;
|
||||
t = t->next;
|
||||
s++;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME: This shares almost all code with activate_multi_custom */
|
||||
static int _reload_custom_multi(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
json_object *jobj_segments,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r, count = json_segments_count(jobj_segments);
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.uuid = crypt_get_uuid(cd),
|
||||
};
|
||||
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* do not allow activation when particular requirements detected */
|
||||
if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0)))
|
||||
return r;
|
||||
|
||||
/* Add persistent activation flags */
|
||||
if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
|
||||
LUKS2_config_get_flags(cd, hdr, &dmd.flags);
|
||||
|
||||
dmd.flags |= (flags | CRYPT_ACTIVATE_SHARED);
|
||||
|
||||
r = dm_targets_allocate(&dmd.segment, count);
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = _prepare_multi_dmd(cd, hdr, vks, jobj_segments, &dmd);
|
||||
if (!r)
|
||||
r = dm_reload_device(cd, name, &dmd, 0, 0);
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_reload(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint32_t flags)
|
||||
{
|
||||
if (crypt_get_integrity_tag_size(cd))
|
||||
return -ENOTSUP;
|
||||
|
||||
return _reload_custom_multi(cd, name, vks,
|
||||
LUKS2_get_segments_jobj(crypt_get_hdr(cd, CRYPT_LUKS2)), flags);
|
||||
}
|
||||
|
||||
int LUKS2_activate_multi(struct crypt_device *cd,
|
||||
const char *name,
|
||||
struct volume_key *vks,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
|
||||
int r, count = json_segments_count(jobj_segments);
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.uuid = crypt_get_uuid(cd),
|
||||
};
|
||||
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* do not allow activation when particular requirements detected */
|
||||
if ((r = LUKS2_unmet_requirements(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 0)))
|
||||
return r;
|
||||
|
||||
/* Add persistent activation flags */
|
||||
if (!(flags & CRYPT_ACTIVATE_IGNORE_PERSISTENT))
|
||||
LUKS2_config_get_flags(cd, hdr, &dmd.flags);
|
||||
|
||||
dmd.flags |= flags;
|
||||
|
||||
r = dm_targets_allocate(&dmd.segment, count);
|
||||
if (r) {
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = _prepare_multi_dmd(cd, hdr, vks, jobj_segments, &dmd);
|
||||
if (!r)
|
||||
r = dm_create_device(cd, name, CRYPT_LUKS2, &dmd);
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_activate(struct crypt_device *cd,
|
||||
@@ -1877,6 +2166,153 @@ int LUKS2_activate(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool is_reencryption_helper(const char *name)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
len = strlen(name);
|
||||
return (len >= 9 && (!strcmp(name + len - 8, "-hotzone") ||
|
||||
!strcmp(name + len - 8, "-overlay")));
|
||||
|
||||
}
|
||||
|
||||
static bool contains_reencryption_helper(char **names)
|
||||
{
|
||||
while (*names) {
|
||||
if (is_reencryption_helper(*names++))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr *hdr, struct crypt_dm_active_device *dmd, uint32_t flags)
|
||||
{
|
||||
int r, ret;
|
||||
struct dm_target *tgt;
|
||||
crypt_status_info ci;
|
||||
struct crypt_dm_active_device dmdc;
|
||||
char **dep, uuid[37], deps_uuid_prefix[38], *deps[65] = { 0 };
|
||||
const char *namei = NULL;
|
||||
struct crypt_lock_handle *reencrypt_lock = NULL;
|
||||
|
||||
if (!dmd || !dmd->uuid)
|
||||
return -EINVAL;
|
||||
|
||||
r = snprintf(deps_uuid_prefix, sizeof(deps_uuid_prefix), "TEMP-%.32s", dmd->uuid + 6);
|
||||
if (r < 0 || (size_t)r != 37)
|
||||
return -EINVAL;
|
||||
|
||||
r = snprintf(uuid, sizeof(uuid), "%.8s-%.4s-%.4s-%.4s-%.12s",
|
||||
dmd->uuid + 6, dmd->uuid + 14, dmd->uuid + 18, dmd->uuid + 22, dmd->uuid + 26);
|
||||
if (r < 0 || (size_t)r != 36)
|
||||
return -EINVAL;
|
||||
|
||||
/* uuid mismatch with metadata (if available) */
|
||||
if (hdr && strcmp(hdr->uuid, uuid))
|
||||
return -EINVAL;
|
||||
|
||||
tgt = &dmd->segment;
|
||||
|
||||
/* TODO: We have LUKS2 dependencies now */
|
||||
if (hdr && single_segment(dmd) && tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
|
||||
namei = device_dm_name(tgt->data_device);
|
||||
|
||||
r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (contains_reencryption_helper(deps)) {
|
||||
r = crypt_reencrypt_lock(cd, uuid, &reencrypt_lock);
|
||||
if (r) {
|
||||
if (r == -EBUSY)
|
||||
log_err(cd, _("Reencryption in-progress. Cannot deactivate device."));
|
||||
else
|
||||
log_err(cd, _("Failed to get reencryption lock."));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dep = deps;
|
||||
while (*dep) {
|
||||
if (is_reencryption_helper(*dep) && (dm_status_suspended(cd, *dep) > 0)) {
|
||||
if (dm_error_device(cd, *dep))
|
||||
log_err(cd, _("Failed to error suspended device %s."), *dep);
|
||||
}
|
||||
dep++;
|
||||
}
|
||||
|
||||
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
|
||||
if (r < 0) {
|
||||
memset(&dmdc, 0, sizeof(dmdc));
|
||||
dmdc.segment.type = DM_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Remove top level device first */
|
||||
r = dm_remove_device(cd, name, flags);
|
||||
if (!r) {
|
||||
tgt = &dmdc.segment;
|
||||
while (tgt) {
|
||||
if (tgt->type == DM_CRYPT)
|
||||
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description, LOGON_KEY);
|
||||
tgt = tgt->next;
|
||||
}
|
||||
}
|
||||
dm_targets_free(cd, &dmdc);
|
||||
|
||||
/* TODO: We have LUKS2 dependencies now */
|
||||
if (r >= 0 && namei) {
|
||||
log_dbg(cd, "Deactivating integrity device %s.", namei);
|
||||
r = dm_remove_device(cd, namei, 0);
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
ret = 0;
|
||||
dep = deps;
|
||||
while (*dep) {
|
||||
log_dbg(cd, "Deactivating LUKS2 dependent device %s.", *dep);
|
||||
r = dm_query_device(cd, *dep, DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE, &dmdc);
|
||||
if (r < 0) {
|
||||
memset(&dmdc, 0, sizeof(dmdc));
|
||||
dmdc.segment.type = DM_UNKNOWN;
|
||||
}
|
||||
|
||||
r = dm_remove_device(cd, *dep, flags);
|
||||
if (r < 0) {
|
||||
ci = crypt_status(cd, *dep);
|
||||
if (ci == CRYPT_BUSY)
|
||||
log_err(cd, _("Device %s is still in use."), *dep);
|
||||
if (ci == CRYPT_INACTIVE)
|
||||
r = 0;
|
||||
}
|
||||
if (!r) {
|
||||
tgt = &dmdc.segment;
|
||||
while (tgt) {
|
||||
if (tgt->type == DM_CRYPT)
|
||||
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description, LOGON_KEY);
|
||||
tgt = tgt->next;
|
||||
}
|
||||
}
|
||||
dm_targets_free(cd, &dmdc);
|
||||
if (r && !ret)
|
||||
ret = r;
|
||||
dep++;
|
||||
}
|
||||
r = ret;
|
||||
}
|
||||
|
||||
out:
|
||||
crypt_reencrypt_unlock(cd, reencrypt_lock);
|
||||
dep = deps;
|
||||
while (*dep)
|
||||
free(*dep++);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet)
|
||||
{
|
||||
uint32_t reqs;
|
||||
@@ -1900,6 +2336,8 @@ int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uin
|
||||
|
||||
if (reqs_reencrypt(reqs) && !quiet)
|
||||
log_err(cd, _("Offline reencryption in progress. Aborting."));
|
||||
if (reqs_reencrypt_online(reqs) && !quiet)
|
||||
log_err(cd, _("Online reencryption in progress. Aborting."));
|
||||
|
||||
/* any remaining unmasked requirement fails the check */
|
||||
return reqs ? -EINVAL : 0;
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
|
||||
/* Internal implementations */
|
||||
extern const keyslot_handler luks2_keyslot;
|
||||
extern const keyslot_handler reenc_keyslot;
|
||||
|
||||
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
|
||||
&luks2_keyslot,
|
||||
&reenc_keyslot,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -75,23 +77,58 @@ int LUKS2_keyslot_find_empty(struct luks2_hdr *hdr)
|
||||
}
|
||||
|
||||
/* Check if a keyslot is asssigned to specific segment */
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
static int _keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
int keyslot_digest, segment_digest;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0;
|
||||
int keyslot_digest, segment_digest, s, count = 0;
|
||||
|
||||
keyslot_digest = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (keyslot_digest < 0)
|
||||
return -EINVAL;
|
||||
return keyslot_digest;
|
||||
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
if (segment_digest < 0)
|
||||
return segment_digest;
|
||||
if (segment >= 0) {
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, segment);
|
||||
return segment_digest == keyslot_digest;
|
||||
}
|
||||
for (s = 0; s < 3; s++) {
|
||||
segment_digest = LUKS2_digest_by_segment(hdr, s);
|
||||
if (segment_digest == keyslot_digest)
|
||||
count++;
|
||||
}
|
||||
|
||||
return segment_digest == keyslot_digest ? 0 : -ENOENT;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int _keyslot_for_digest(struct luks2_hdr *hdr, int keyslot, int digest)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
|
||||
r = LUKS2_digest_by_keyslot(hdr, keyslot);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return r == digest ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_for_segment(struct luks2_hdr *hdr, int keyslot, int segment)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
|
||||
/* no need to check anything */
|
||||
if (segment == CRYPT_ANY_SEGMENT)
|
||||
return 0; /* ok */
|
||||
if (segment == CRYPT_DEFAULT_SEGMENT) {
|
||||
segment = LUKS2_get_default_segment(hdr);
|
||||
if (segment < 0)
|
||||
return segment;
|
||||
}
|
||||
|
||||
r = _keyslot_for_segment(hdr, keyslot, segment);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (segment == CRYPT_ONE_SEGMENT)
|
||||
log_dbg(NULL, "At least one segment variant");
|
||||
|
||||
return r >= 1 ? 0 : -ENOENT;
|
||||
}
|
||||
|
||||
/* Number of keyslots assigned to a segment or all keyslots for CRYPT_ANY_SEGMENT */
|
||||
@@ -266,15 +303,58 @@ int LUKS2_keyslot_area(struct luks2_hdr *hdr,
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "offset", &jobj))
|
||||
return -EINVAL;
|
||||
*offset = json_object_get_int64(jobj);
|
||||
*offset = json_object_get_uint64(jobj);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_area, "size", &jobj))
|
||||
return -EINVAL;
|
||||
*length = json_object_get_int64(jobj);
|
||||
*length = json_object_get_uint64(jobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int key_size, r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)))
|
||||
return -ENOENT;
|
||||
|
||||
r = _keyslot_for_digest(hdr, keyslot, digest);
|
||||
if (r) {
|
||||
if (r == -ENOENT)
|
||||
log_dbg(cd, "Keyslot %d unusable for digest %d.", keyslot, digest);
|
||||
return r;
|
||||
}
|
||||
|
||||
key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
|
||||
if (key_size < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*vk = crypt_alloc_volume_key(key_size, NULL);
|
||||
if (!*vk)
|
||||
return -ENOMEM;
|
||||
|
||||
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
|
||||
if (r < 0)
|
||||
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
|
||||
else
|
||||
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
|
||||
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
}
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -321,11 +401,50 @@ static int LUKS2_open_and_verify(struct crypt_device *cd,
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vk);
|
||||
*vk = NULL;
|
||||
}
|
||||
} else
|
||||
crypt_volume_key_set_id(*vk, r);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
crypt_keyslot_priority priority,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
int digest,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
json_object *jobj_keyslots, *jobj;
|
||||
crypt_keyslot_priority slot_priority;
|
||||
int keyslot, r = -ENOENT;
|
||||
|
||||
json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots);
|
||||
|
||||
json_object_object_foreach(jobj_keyslots, slot, val) {
|
||||
if (!json_object_object_get_ex(val, "priority", &jobj))
|
||||
slot_priority = CRYPT_SLOT_PRIORITY_NORMAL;
|
||||
else
|
||||
slot_priority = json_object_get_int(jobj);
|
||||
|
||||
keyslot = atoi(slot);
|
||||
if (slot_priority != priority) {
|
||||
log_dbg(cd, "Keyslot %d priority %d != %d (required), skipped.",
|
||||
keyslot, slot_priority, priority);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
/* Do not retry for errors that are no -EPERM or -ENOENT,
|
||||
former meaning password wrong, latter key slot unusable for segment */
|
||||
if ((r != -EPERM) && (r != -ENOENT))
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
crypt_keyslot_priority priority,
|
||||
@@ -364,6 +483,76 @@ static int LUKS2_keyslot_open_priority(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int LUKS2_keyslot_open_by_digest(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
int digest,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vk)
|
||||
{
|
||||
int r_prio, r = -EINVAL;
|
||||
|
||||
if (digest < 0)
|
||||
return r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT) {
|
||||
r_prio = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
|
||||
password, password_len, digest, vk);
|
||||
if (r_prio >= 0)
|
||||
r = r_prio;
|
||||
else if (r_prio != -EPERM && r_prio != -ENOENT)
|
||||
r = r_prio;
|
||||
else
|
||||
r = LUKS2_keyslot_open_priority_digest(cd, hdr, CRYPT_SLOT_PRIORITY_NORMAL,
|
||||
password, password_len, digest, vk);
|
||||
/* Prefer password wrong to no entry from priority slot */
|
||||
if (r_prio == -EPERM && r == -ENOENT)
|
||||
r = r_prio;
|
||||
} else
|
||||
r = LUKS2_open_and_verify_by_digest(cd, hdr, keyslot, digest, password, password_len, vk);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open_all_segments(struct crypt_device *cd,
|
||||
int keyslot_old,
|
||||
int keyslot_new,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
struct volume_key **vks)
|
||||
{
|
||||
struct volume_key *vk;
|
||||
int digest_old, digest_new, r = -EINVAL;
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
digest_old = LUKS2_reencrypt_digest_old(hdr);
|
||||
if (digest_old >= 0) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_old, keyslot_old);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_old, digest_old, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_set_id(vk, digest_old);
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
|
||||
digest_new = LUKS2_reencrypt_digest_new(hdr);
|
||||
if (digest_new >= 0 && digest_old != digest_new) {
|
||||
log_dbg(cd, "Trying to unlock volume key (digest: %d) using keyslot %d.", digest_new, keyslot_new);
|
||||
r = LUKS2_keyslot_open_by_digest(cd, hdr, keyslot_new, digest_new, password, password_len, &vk);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
crypt_volume_key_set_id(vk, digest_new);
|
||||
crypt_volume_key_add_next(vks, vk);
|
||||
}
|
||||
out:
|
||||
if (r < 0) {
|
||||
crypt_free_volume_key(*vks);
|
||||
*vks = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
int segment,
|
||||
@@ -395,6 +584,64 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
return r;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: find keyslot by type */
|
||||
h = LUKS2_keyslot_handler_type(cd, "reencrypt");
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
r = reenc_keyslot_alloc(cd, hdr, keyslot, params);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_reencrypt_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const void *buffer,
|
||||
size_t buffer_length)
|
||||
{
|
||||
const keyslot_handler *h;
|
||||
int r;
|
||||
|
||||
if (!(h = LUKS2_keyslot_handler(cd, keyslot)) || strcmp(h->name, "reencrypt"))
|
||||
return -EINVAL;
|
||||
|
||||
r = h->validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
|
||||
if (r) {
|
||||
log_dbg(cd, "Keyslot validation failed.");
|
||||
return r;
|
||||
}
|
||||
|
||||
return h->store(cd, keyslot, NULL, 0,
|
||||
buffer, buffer_length);
|
||||
}
|
||||
|
||||
int LUKS2_keyslot_store(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
@@ -664,3 +911,46 @@ void LUKS2_keyslots_repair(struct crypt_device *cd, json_object *jobj_keyslots)
|
||||
h->repair(cd, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* assumes valid header */
|
||||
int LUKS2_find_keyslot(struct luks2_hdr *hdr, const char *type)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_keyslot, *jobj_type;
|
||||
|
||||
if (!type)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
|
||||
if (!jobj_keyslot)
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
|
||||
if (!strcmp(json_object_get_string(jobj_type), type))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int LUKS2_find_keyslot_for_segment(struct luks2_hdr *hdr, int segment, const char *type)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_keyslot, *jobj_type;
|
||||
|
||||
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) {
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, i);
|
||||
if (!jobj_keyslot)
|
||||
continue;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "type", &jobj_type);
|
||||
if (strcmp(json_object_get_string(jobj_type), type))
|
||||
continue;
|
||||
|
||||
if (!LUKS2_keyslot_for_segment(hdr, i, segment))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
300
lib/luks2/luks2_keyslot_reenc.c
Normal file
300
lib/luks2/luks2_keyslot_reenc.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
|
||||
*
|
||||
* Copyright (C) 2016-2018, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2016-2018, Ondrej Kozina
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "luks2_internal.h"
|
||||
|
||||
static int reenc_keyslot_open(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password,
|
||||
size_t password_len,
|
||||
char *volume_key,
|
||||
size_t volume_key_len)
|
||||
{
|
||||
return -ENOENT; /* TODO: */
|
||||
}
|
||||
|
||||
int reenc_keyslot_alloc(struct crypt_device *cd,
|
||||
struct luks2_hdr *hdr,
|
||||
int keyslot,
|
||||
const struct crypt_params_reencrypt *params)
|
||||
{
|
||||
int r;
|
||||
json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
|
||||
uint64_t area_offset, area_length;
|
||||
|
||||
log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
|
||||
|
||||
if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
|
||||
return -EINVAL;
|
||||
|
||||
/* encryption doesn't require area (we shift data and backup will be available) */
|
||||
if (!params->data_shift) {
|
||||
r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else { /* we can't have keyslot w/o area...bug? */
|
||||
r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
jobj_keyslot = json_object_new_object();
|
||||
if (!jobj_keyslot)
|
||||
return -ENOMEM;
|
||||
|
||||
jobj_area = json_object_new_object();
|
||||
|
||||
if (params->data_shift) {
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("datashift"));
|
||||
json_object_object_add(jobj_area, "shift_size", json_object_new_uint64(params->data_shift << SECTOR_SHIFT));
|
||||
} else
|
||||
/* except data shift protection, initial setting is irrelevant. Type can be changed during reencryption */
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
|
||||
json_object_object_add(jobj_area, "offset", json_object_new_uint64(area_offset));
|
||||
json_object_object_add(jobj_area, "size", json_object_new_uint64(area_length));
|
||||
|
||||
json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
|
||||
json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
|
||||
json_object_object_add(jobj_keyslot, "mode", json_object_new_string(params->mode));
|
||||
if (params->direction == CRYPT_REENCRYPT_FORWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
|
||||
else if (params->direction == CRYPT_REENCRYPT_BACKWARD)
|
||||
json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_add(jobj_keyslot, "area", jobj_area);
|
||||
|
||||
json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
|
||||
if (LUKS2_check_json_size(cd, hdr)) {
|
||||
log_dbg(cd, "New keyslot too large to fit in free metadata space.");
|
||||
json_object_object_del_by_uint(jobj_keyslots, keyslot);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
log_dbg(cd, "JSON: %s", json_object_to_json_string_ext(hdr->jobj, JSON_C_TO_STRING_PRETTY));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store_data(struct crypt_device *cd,
|
||||
json_object *jobj_keyslot,
|
||||
const void *buffer, size_t buffer_len)
|
||||
{
|
||||
int devfd, r;
|
||||
json_object *jobj_area, *jobj_offset, *jobj_length;
|
||||
uint64_t area_offset, area_length;
|
||||
struct device *device = crypt_metadata_device(cd);
|
||||
|
||||
if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
|
||||
!json_object_object_get_ex(jobj_area, "size", &jobj_length))
|
||||
return -EINVAL;
|
||||
|
||||
area_offset = json_object_get_uint64(jobj_offset);
|
||||
area_length = json_object_get_uint64(jobj_length);
|
||||
|
||||
if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
|
||||
return -EINVAL;
|
||||
|
||||
r = device_write_lock(cd, device);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to acquire write lock on device %s."),
|
||||
device_path(device));
|
||||
return r;
|
||||
}
|
||||
|
||||
devfd = device_open_locked(cd, device, O_RDWR);
|
||||
if (devfd >= 0) {
|
||||
if (write_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), CONST_CAST(void *)buffer,
|
||||
buffer_len, area_offset) < 0)
|
||||
r = -EIO;
|
||||
else
|
||||
r = 0;
|
||||
close(devfd);
|
||||
} else
|
||||
r = -EINVAL;
|
||||
|
||||
device_write_unlock(cd, device);
|
||||
|
||||
if (r)
|
||||
log_err(cd, _("IO error while encrypting keyslot."));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_store(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *password __attribute__((unused)),
|
||||
size_t password_len __attribute__((unused)),
|
||||
const char *buffer,
|
||||
size_t buffer_len)
|
||||
{
|
||||
struct luks2_hdr *hdr;
|
||||
json_object *jobj_keyslot;
|
||||
int r = 0;
|
||||
|
||||
if (!cd || !buffer || !buffer_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = LUKS2_hdr_write(cd, hdr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return keyslot;
|
||||
}
|
||||
|
||||
int reenc_keyslot_update(struct crypt_device *cd,
|
||||
const struct luks2_reenc_context *rh)
|
||||
{
|
||||
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
|
||||
if (!jobj_keyslot)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
|
||||
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
|
||||
|
||||
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for checksum protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("checksum"));
|
||||
json_object_object_add(jobj_area, "hash", json_object_new_string(rh->rp.p.csum.hash));
|
||||
json_object_object_add(jobj_area, "sector_size", json_object_new_int64(rh->alignment));
|
||||
} else if (rh->rp.type == REENC_PROTECTION_NOOP) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("none"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
|
||||
log_dbg(cd, "Updating reencrypt keyslot for journal protection.");
|
||||
json_object_object_add(jobj_area, "type", json_object_new_string("journal"));
|
||||
json_object_object_del(jobj_area, "hash");
|
||||
} else
|
||||
log_dbg(cd, "No update of reencrypt keyslot needed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
|
||||
{
|
||||
json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size;
|
||||
const char *mode, *type;
|
||||
uint32_t sector_size;
|
||||
uint64_t shift_size;
|
||||
|
||||
/* mode (string: encrypt,reencrypt,decrypt)
|
||||
* direction (string:)
|
||||
* area {
|
||||
* type: (string: datashift, journal, checksum, none)
|
||||
* hash: (string: checksum only)
|
||||
* sector_size (uint32: checksum only)
|
||||
* shift_size (uint64: datashift only)
|
||||
* }
|
||||
*/
|
||||
|
||||
/* area and area type are validated in general validation code */
|
||||
if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
|
||||
!json_object_object_get_ex(jobj_area, "type", &jobj_type))
|
||||
return -EINVAL;
|
||||
|
||||
jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string);
|
||||
|
||||
if (!jobj_mode || !json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string))
|
||||
return -EINVAL;
|
||||
|
||||
mode = json_object_get_string(jobj_mode);
|
||||
type = json_object_get_string(jobj_type);
|
||||
|
||||
if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
|
||||
strcmp(mode, "decrypt")) {
|
||||
log_dbg(cd, "Illegal reencrypt mode %s.", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(type, "checksum")) {
|
||||
jobj_hash = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "hash", json_type_string);
|
||||
jobj_sector_size = json_contains(cd, jobj_area, "type:checksum", "Keyslot area", "sector_size", json_type_int);
|
||||
if (!jobj_hash || !jobj_sector_size)
|
||||
return -EINVAL;
|
||||
if (!validate_json_uint32(jobj_sector_size))
|
||||
return -EINVAL;
|
||||
sector_size = json_object_get_uint32(jobj_sector_size);
|
||||
if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
|
||||
log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.", sector_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strcmp(type, "datashift")) {
|
||||
if (!(jobj_shift_size = json_contains(cd, jobj_area, "type:datashift", "Keyslot area", "shift_size", json_type_string)))
|
||||
return -EINVAL;
|
||||
|
||||
shift_size = json_object_get_uint64(jobj_shift_size);
|
||||
if (!shift_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (MISALIGNED_512(shift_size)) {
|
||||
log_dbg(cd, "Shift size field has to be aligned to sector size: %" PRIu32, SECTOR_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const keyslot_handler reenc_keyslot = {
|
||||
.name = "reencrypt",
|
||||
.open = reenc_keyslot_open,
|
||||
.store = reenc_keyslot_store, /* initialization only or also per every chunk write */
|
||||
.wipe = reenc_keyslot_wipe,
|
||||
.dump = reenc_keyslot_dump,
|
||||
.validate = reenc_keyslot_validate
|
||||
};
|
||||
@@ -24,6 +24,14 @@
|
||||
#include "../luks1/luks.h"
|
||||
#include "../luks1/af.h"
|
||||
|
||||
int LUKS2_check_cipher(struct crypt_device *cd,
|
||||
size_t keylength,
|
||||
const char *cipher,
|
||||
const char *cipher_mode)
|
||||
{
|
||||
return LUKS_check_cipher(cd, keylength, cipher, cipher_mode);
|
||||
}
|
||||
|
||||
static int json_luks1_keyslot(const struct luks_phdr *hdr_v1, int keyslot, struct json_object **keyslot_object)
|
||||
{
|
||||
char *base64_str, cipher[LUKS_CIPHERNAME_L+LUKS_CIPHERMODE_L];
|
||||
|
||||
3108
lib/luks2/luks2_reencrypt.c
Normal file
3108
lib/luks2/luks2_reencrypt.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned b
|
||||
json_object_object_foreach(jobj_segments, key, val) {
|
||||
UNUSED(key);
|
||||
|
||||
if (LUKS2_segment_ignore(val))
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
|
||||
tmp = json_segment_get_offset(val, blockwise);
|
||||
@@ -133,6 +133,37 @@ json_object *json_segment_get_flags(json_object *jobj_segment)
|
||||
return jobj;
|
||||
}
|
||||
|
||||
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
|
||||
{
|
||||
int r, i;
|
||||
json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
|
||||
|
||||
if (!jobj_flags)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_flags, i);
|
||||
if (len)
|
||||
r = strncmp(json_object_get_string(jobj), flag_str, len);
|
||||
else
|
||||
r = strcmp(json_object_get_string(jobj), flag_str);
|
||||
if (!r)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_segment_is_backup(json_object *jobj_segment)
|
||||
{
|
||||
return json_segment_contains_flag(jobj_segment, "backup-", 7);
|
||||
}
|
||||
|
||||
bool json_segment_is_reencrypt(json_object *jobj_segment)
|
||||
{
|
||||
return json_segment_contains_flag(jobj_segment, "in-reencryption", 0);
|
||||
}
|
||||
|
||||
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
|
||||
{
|
||||
json_object *jobj;
|
||||
@@ -156,7 +187,7 @@ int json_segments_count(json_object *jobj_segments)
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
UNUSED(slot);
|
||||
if (!LUKS2_segment_ignore(val))
|
||||
if (!json_segment_is_backup(val))
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -255,28 +286,6 @@ json_object *json_segment_create_crypt(uint64_t offset,
|
||||
return jobj;
|
||||
}
|
||||
|
||||
int LUKS2_segment_ignore(json_object *jobj_segment)
|
||||
{
|
||||
int i;
|
||||
json_object *jobj_flags, *jobj;
|
||||
|
||||
if (!jobj_segment)
|
||||
return 0;
|
||||
|
||||
json_object_object_get_ex(jobj_segment, "flags", &jobj_flags);
|
||||
|
||||
if (!jobj_flags)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
|
||||
jobj = json_object_array_get_idx(jobj_flags, i);
|
||||
if (!strncmp(json_object_get_string(jobj), "reencrypt-", 10))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
|
||||
{
|
||||
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
|
||||
@@ -319,7 +328,7 @@ int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
return -1;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (LUKS2_segment_ignore(val))
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
@@ -343,7 +352,7 @@ int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
|
||||
return -EINVAL;
|
||||
|
||||
json_object_object_foreach(jobj_segments, slot, val) {
|
||||
if (LUKS2_segment_ignore(val))
|
||||
if (json_segment_is_backup(val))
|
||||
continue;
|
||||
if (strcmp(type, json_segment_type(val) ?: ""))
|
||||
continue;
|
||||
@@ -442,7 +451,7 @@ json_object *LUKS2_get_ignored_segments(struct luks2_hdr *hdr)
|
||||
|
||||
json_object_object_foreach(jobj_segments, key, value) {
|
||||
UNUSED(key);
|
||||
if (LUKS2_segment_ignore(value))
|
||||
if (json_segment_is_backup(value))
|
||||
json_object_object_add_by_uint(jobj, i++, json_object_get(value));
|
||||
}
|
||||
|
||||
|
||||
338
lib/setup.c
338
lib/setup.c
@@ -77,6 +77,7 @@ struct crypt_device {
|
||||
char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
|
||||
char *keyslot_cipher;
|
||||
unsigned int keyslot_key_size;
|
||||
struct luks2_reenc_context *rh;
|
||||
} luks2;
|
||||
struct { /* used in CRYPT_PLAIN */
|
||||
struct crypt_params_plain hdr;
|
||||
@@ -338,7 +339,7 @@ static int onlyLUKS(struct crypt_device *cd)
|
||||
return _onlyLUKS(cd, 0);
|
||||
}
|
||||
|
||||
static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags)
|
||||
static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags, uint32_t mask)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
@@ -357,12 +358,19 @@ static int _onlyLUKS2(struct crypt_device *cd, uint32_t cdflags)
|
||||
if (r || (cdflags & CRYPT_CD_UNRESTRICTED))
|
||||
return r;
|
||||
|
||||
return LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, 0, cdflags & CRYPT_CD_QUIET);
|
||||
return LUKS2_unmet_requirements(cd, &cd->u.luks2.hdr, mask, cdflags & CRYPT_CD_QUIET);
|
||||
}
|
||||
|
||||
static int onlyLUKS2(struct crypt_device *cd)
|
||||
/* Internal only */
|
||||
int onlyLUKS2(struct crypt_device *cd)
|
||||
{
|
||||
return _onlyLUKS2(cd, 0);
|
||||
return _onlyLUKS2(cd, 0, 0);
|
||||
}
|
||||
|
||||
/* Internal only */
|
||||
int onlyLUKS2mask(struct crypt_device *cd, uint32_t mask)
|
||||
{
|
||||
return _onlyLUKS2(cd, 0, mask);
|
||||
}
|
||||
|
||||
static void crypt_set_null_type(struct crypt_device *cd)
|
||||
@@ -629,7 +637,12 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
|
||||
if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
|
||||
!isINTEGRITY(cd->type)) {
|
||||
log_err(cd, _("This operation is not supported for this device type."));
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (isLUKS2(cd->type) && crypt_get_reenc_context(cd)) {
|
||||
log_err(cd, _("Illegal operation with reencryption in-progress."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return _crypt_set_data_device(cd, device);
|
||||
@@ -697,6 +710,7 @@ static int _crypt_load_luks2(struct crypt_device *cd, int reload, int repair)
|
||||
r = 0;
|
||||
memcpy(&cd->u.luks2.hdr, &hdr2, sizeof(hdr2));
|
||||
cd->u.luks2.keyslot_cipher = NULL;
|
||||
cd->u.luks2.rh = NULL;
|
||||
|
||||
out:
|
||||
if (r) {
|
||||
@@ -1048,6 +1062,7 @@ static void crypt_free_type(struct crypt_device *cd)
|
||||
free(cd->u.plain.cipher);
|
||||
free(cd->u.plain.cipher_spec);
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
LUKS2_reenc_context_free(cd, cd->u.luks2.rh);
|
||||
LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
|
||||
free(cd->u.luks2.keyslot_cipher);
|
||||
} else if (isLUKS1(cd->type)) {
|
||||
@@ -1095,20 +1110,21 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!single_segment(&dmd) || tgt->type != DM_CRYPT) {
|
||||
/* TODO: segment count */
|
||||
if (!(tgt->type == DM_CRYPT || tgt->type == DM_LINEAR)) {
|
||||
log_dbg(cd, "Unsupported device table detected in %s.", name);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_parse_name_and_mode(tgt->u.crypt.cipher, cipher,
|
||||
r = crypt_parse_name_and_mode(tgt->type == DM_LINEAR ? "null" : tgt->u.crypt.cipher, cipher,
|
||||
&key_nums, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Cannot parse cipher and mode from active device.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
|
||||
if (tgt->type == DM_CRYPT && tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
|
||||
r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
@@ -1299,11 +1315,13 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
|
||||
r = dm_query_device(NULL, name, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &dmd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!single_segment(&dmd)) {
|
||||
/* TODO: segment count */
|
||||
/*
|
||||
if (dmd.segment_count > 4) {
|
||||
log_dbg(NULL, "Unsupported device table detected in %s.", name);
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}*/
|
||||
|
||||
*cd = NULL;
|
||||
|
||||
@@ -1353,7 +1371,7 @@ int crypt_init_by_name_and_header(struct crypt_device **cd,
|
||||
|
||||
/* Try to initialise basic parameters from active device */
|
||||
|
||||
if (tgt->type == DM_CRYPT)
|
||||
if (tgt->type == DM_CRYPT || tgt->type == DM_LINEAR)
|
||||
r = _init_by_name_crypt(*cd, name);
|
||||
else if (tgt->type == DM_VERITY)
|
||||
r = _init_by_name_verity(*cd, name);
|
||||
@@ -2849,7 +2867,6 @@ void crypt_free(struct crypt_device *cd)
|
||||
|
||||
free(CONST_CAST(void*)cd->pbkdf.type);
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
|
||||
crypt_free_type(cd);
|
||||
|
||||
/* Some structures can contain keys (TCRYPT), wipe it */
|
||||
@@ -3623,9 +3640,215 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = vks;
|
||||
|
||||
while (vk) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk));
|
||||
if (r < 0)
|
||||
return r;
|
||||
vk = vk->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See fixmes in _open_and_activate_luks2 */
|
||||
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
|
||||
|
||||
/* TODO: This function should 1:1 with pre-reencryption code */
|
||||
static int _open_and_activate(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
int r;
|
||||
struct volume_key *vk = NULL;
|
||||
|
||||
r = LUKS2_keyslot_open(cd, keyslot,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
passphrase, passphrase_size, &vk);
|
||||
if (r < 0)
|
||||
return r;
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
|
||||
crypt_use_keyring_for_vk(cd)) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
|
||||
&cd->u.luks2.hdr, vk, keyslot);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
out:
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vk);
|
||||
crypt_free_volume_key(vk);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
static int _open_and_activate_reencrypt_device(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
uint64_t device_size;
|
||||
bool use_keyring, keys_ready = false;
|
||||
struct volume_key *vks = NULL;
|
||||
int r = 0;
|
||||
struct crypt_lock_handle *reencrypt_lock = NULL;
|
||||
struct luks2_reenc_context *rh = NULL;
|
||||
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
if (name)
|
||||
r = crypt_reencrypt_lock(cd, NULL, &reencrypt_lock);
|
||||
if (r) {
|
||||
if (r == -EBUSY)
|
||||
log_err(cd, _("Reencryption in-progress. Cannot activate device."));
|
||||
else
|
||||
log_err(cd, _("Failed to get reencryption lock."));
|
||||
return r;
|
||||
}
|
||||
|
||||
if (name && (r = crypt_load(cd, CRYPT_LUKS2, NULL)))
|
||||
goto err;
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
|
||||
if (name && (r = luks2_check_device_size(cd, hdr, &device_size, true)))
|
||||
goto err;
|
||||
|
||||
if (name && ri == CRYPT_REENCRYPT_CRASH) {
|
||||
log_dbg(cd, _("Entering reencryption crash recovery."));
|
||||
|
||||
r = LUKS2_reenc_load(cd, hdr, device_size, NULL, &rh);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Failed to load reencryption context from LUKS2 header."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = LUKS2_keyslot_open_all_segments(cd, keyslot, keyslot, passphrase, passphrase_size, &vks);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
keyslot = r;
|
||||
|
||||
r = LUKS2_verify_and_upload_keys(cd, hdr, rh->digest_old, rh->digest_new, vks);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to verify and upload keys for recovery."));
|
||||
goto err;
|
||||
}
|
||||
|
||||
keys_ready = true;
|
||||
r = LUKS2_reenc_recover(cd, hdr, rh, vks);
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
if ((r = LUKS2_reenc_update_segments(cd, hdr, rh)))
|
||||
goto err;
|
||||
|
||||
/* FIXME: Create unified cleanup routine when reencryption is finished */
|
||||
if (LUKS2_segments_count(hdr) == 1) {
|
||||
/* FIXME: remove also keyslots assigned to old digest */
|
||||
crypt_keyslot_destroy(cd, rh->reenc_keyslot);
|
||||
reenc_erase_backup_segments(cd, hdr);
|
||||
if (update_reencryption_flag(cd, 0, true)) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
LUKS2_reenc_context_free(cd, rh);
|
||||
rh = NULL;
|
||||
}
|
||||
|
||||
/* recovery finished reencryption or it's already finished */
|
||||
if (ri == CRYPT_REENCRYPT_NONE) {
|
||||
crypt_free_volume_key(vks);
|
||||
crypt_reencrypt_unlock(cd, reencrypt_lock);
|
||||
return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags);
|
||||
}
|
||||
|
||||
if (ri > CRYPT_REENCRYPT_CLEAN && name) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
use_keyring = (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
|
||||
crypt_use_keyring_for_vk(cd);
|
||||
if (use_keyring)
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
|
||||
if (!keys_ready) {
|
||||
log_dbg(cd, "Entering clean reencryption state mode.");
|
||||
/* we need all keys in this case */
|
||||
if (use_keyring || name)
|
||||
r = LUKS2_keyslot_open_all_segments(cd, keyslot, keyslot, passphrase, passphrase_size, &vks);
|
||||
else
|
||||
/* allow user to test passphrase only for whatever keyslot */
|
||||
r = LUKS2_keyslot_open(cd, keyslot, CRYPT_ANY_SEGMENT, passphrase, passphrase_size, &vks);
|
||||
if (r >= 0)
|
||||
keyslot = r;
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
keys_ready = true;
|
||||
}
|
||||
|
||||
if (use_keyring && keys_ready)
|
||||
r = load_all_keys(cd, hdr, vks);
|
||||
|
||||
if (r >= 0 && name)
|
||||
r = LUKS2_activate_multi(cd, name, vks, flags);
|
||||
err:
|
||||
crypt_reencrypt_unlock(cd, reencrypt_lock);
|
||||
if (r < 0)
|
||||
crypt_drop_keyring_key(cd, vks);
|
||||
crypt_free_volume_key(vks);
|
||||
|
||||
return r < 0 ? r : keyslot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activation/deactivation of a device
|
||||
*/
|
||||
static int _open_and_activate_luks2(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
const char *name,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
int r;
|
||||
struct luks2_hdr *hdr = &cd->u.luks2.hdr;
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (ri > CRYPT_REENCRYPT_NONE)
|
||||
r = _open_and_activate_reencrypt_device(cd, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
else
|
||||
r = _open_and_activate(cd, keyslot, name, passphrase,
|
||||
passphrase_size, flags);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
@@ -3672,25 +3895,8 @@ static int _activate_by_passphrase(struct crypt_device *cd,
|
||||
r = LUKS1_activate(cd, name, vk, flags);
|
||||
}
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
r = LUKS2_keyslot_open(cd, keyslot,
|
||||
(flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ?
|
||||
CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
|
||||
passphrase, passphrase_size, &vk);
|
||||
if (r >= 0) {
|
||||
keyslot = r;
|
||||
|
||||
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
|
||||
crypt_use_keyring_for_vk(cd)) {
|
||||
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
|
||||
&cd->u.luks2.hdr, vk, keyslot);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
|
||||
}
|
||||
|
||||
if (name)
|
||||
r = LUKS2_activate(cd, name, vk, flags);
|
||||
}
|
||||
r = _open_and_activate_luks2(cd, keyslot, name, passphrase, passphrase_size, flags);
|
||||
keyslot = r;
|
||||
} else {
|
||||
log_err(cd, _("Device type is not properly initialised."));
|
||||
r = -EINVAL;
|
||||
@@ -3975,13 +4181,11 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||
|
||||
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||
{
|
||||
char *key_desc;
|
||||
struct crypt_device *fake_cd = NULL;
|
||||
const char *namei = NULL;
|
||||
struct luks2_hdr *hdr2 = NULL;
|
||||
struct crypt_dm_active_device dmd = {};
|
||||
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_UUID | DM_ACTIVE_HOLDERS;
|
||||
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
@@ -4009,26 +4213,21 @@ int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t
|
||||
r = -EBUSY;
|
||||
break;
|
||||
}
|
||||
if (isLUKS2(cd->type) && single_segment(&dmd) && tgt->type == DM_CRYPT && crypt_get_integrity_tag_size(cd))
|
||||
namei = device_dm_name(tgt->data_device);
|
||||
}
|
||||
|
||||
key_desc = crypt_get_device_key_description(cd, name);
|
||||
if (isLUKS2(cd->type))
|
||||
hdr2 = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
if (isTCRYPT(cd->type))
|
||||
if (!strncmp(CRYPT_LUKS2, dmd.uuid ?: "", sizeof(CRYPT_LUKS2)-1) || hdr2)
|
||||
r = LUKS2_deactivate(cd, name, hdr2, &dmd, flags);
|
||||
else if (isTCRYPT(cd->type))
|
||||
r = TCRYPT_deactivate(cd, name, flags);
|
||||
else
|
||||
r = dm_remove_device(cd, name, flags);
|
||||
if (r < 0 && crypt_status(cd, name) == CRYPT_BUSY) {
|
||||
log_err(cd, _("Device %s is still in use."), name);
|
||||
r = -EBUSY;
|
||||
} else if (namei) {
|
||||
log_dbg(cd, "Deactivating integrity device %s.", namei);
|
||||
r = dm_remove_device(cd, namei, 0);
|
||||
}
|
||||
if (!r)
|
||||
crypt_drop_keyring_key_by_description(cd, key_desc, LOGON_KEY);
|
||||
free(key_desc);
|
||||
break;
|
||||
case CRYPT_INACTIVE:
|
||||
log_err(cd, _("Device %s is not active."), name);
|
||||
@@ -4040,6 +4239,7 @@ int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t
|
||||
}
|
||||
|
||||
dm_targets_free(cd, &dmd);
|
||||
free(CONST_CAST(void*)dmd.uuid);
|
||||
crypt_free(fake_cd);
|
||||
|
||||
return r;
|
||||
@@ -4991,6 +5191,18 @@ void *crypt_get_hdr(struct crypt_device *cd, const char *type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd)
|
||||
{
|
||||
return cd->u.luks2.rh;
|
||||
}
|
||||
|
||||
/* internal only */
|
||||
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh)
|
||||
{
|
||||
cd->u.luks2.rh = rh;
|
||||
}
|
||||
|
||||
/*
|
||||
* Token handling
|
||||
*/
|
||||
@@ -5002,7 +5214,7 @@ int crypt_activate_by_token(struct crypt_device *cd,
|
||||
log_dbg(cd, "%s volume %s using token %d.",
|
||||
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, 0)))
|
||||
return r;
|
||||
|
||||
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd))
|
||||
@@ -5026,7 +5238,7 @@ int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
|
||||
|
||||
log_dbg(cd, "Requesting JSON for token %d.", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
return LUKS2_token_json_get(cd, &cd->u.luks2.hdr, token, json) ?: token;
|
||||
@@ -5046,7 +5258,7 @@ int crypt_token_json_set(struct crypt_device *cd, int token, const char *json)
|
||||
|
||||
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const char **type)
|
||||
{
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED))
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
|
||||
return CRYPT_TOKEN_INVALID;
|
||||
|
||||
return LUKS2_token_status(cd, &cd->u.luks2.hdr, token, type);
|
||||
@@ -5065,7 +5277,7 @@ int crypt_token_luks2_keyring_get(struct crypt_device *cd,
|
||||
|
||||
log_dbg(cd, "Requesting LUKS2 keyring token %d.", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
token_info = LUKS2_token_status(cd, &cd->u.luks2.hdr, token, &type);
|
||||
@@ -5131,7 +5343,7 @@ int crypt_token_is_assigned(struct crypt_device *cd, int token, int keyslot)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token);
|
||||
@@ -5175,7 +5387,7 @@ int crypt_persistent_flags_get(struct crypt_device *cd, crypt_flags_type type, u
|
||||
if (!flags)
|
||||
return -EINVAL;
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED)))
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_UNRESTRICTED, 0)))
|
||||
return r;
|
||||
|
||||
if (type == CRYPT_FLAGS_ACTIVATION)
|
||||
@@ -5521,6 +5733,30 @@ void crypt_serialize_unlock(struct crypt_device *cd)
|
||||
cd->pbkdf_memory_hard_lock = NULL;
|
||||
}
|
||||
|
||||
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
|
||||
struct crypt_params_reencrypt *params)
|
||||
{
|
||||
crypt_reencrypt_info ri;
|
||||
struct luks2_hdr *hdr;
|
||||
|
||||
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
|
||||
return CRYPT_REENCRYPT_INVALID;
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
|
||||
ri = LUKS2_reenc_status(hdr);
|
||||
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params)
|
||||
return ri;
|
||||
|
||||
params->mode = LUKS2_reencrypt_mode(hdr);
|
||||
params->resilience = LUKS2_reencrypt_protection_type(hdr);
|
||||
params->hash = LUKS2_reencrypt_protection_hash(hdr);
|
||||
params->data_shift = LUKS2_reencrypt_data_shift(hdr);
|
||||
params->max_hotzone_size = 0;
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static void __attribute__((destructor)) libcryptsetup_exit(void)
|
||||
{
|
||||
crypt_backend_destroy();
|
||||
|
||||
@@ -280,6 +280,19 @@ int device_open(struct crypt_device *cd, struct device *device, int flags)
|
||||
return device_open_internal(cd, device, flags);
|
||||
}
|
||||
|
||||
int device_open_excl(struct crypt_device *cd, struct device *device, int flags)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(device_path(device), &st))
|
||||
return -EINVAL;
|
||||
if (S_ISBLK(st.st_mode))
|
||||
flags |= O_EXCL;
|
||||
|
||||
assert(!device_locked(device->lh));
|
||||
return device_open_internal(cd, device, flags);
|
||||
}
|
||||
|
||||
int device_open_locked(struct crypt_device *cd, struct device *device, int flags)
|
||||
{
|
||||
assert(!crypt_metadata_locking_enabled() || device_locked(device->lh));
|
||||
|
||||
@@ -16,6 +16,7 @@ lib/utils_wipe.c
|
||||
lib/utils_keyring.c
|
||||
lib/utils_blkid.c
|
||||
lib/utils_io.c
|
||||
lib/utils_storage_wrappers.c
|
||||
lib/luks1/af.c
|
||||
lib/luks1/keyencryption.c
|
||||
lib/luks1/keymanage.c
|
||||
@@ -32,7 +33,10 @@ lib/luks2/luks2_json_format.c
|
||||
lib/luks2/luks2_json_metadata.c
|
||||
lib/luks2/luks2_keyslot.c
|
||||
lib/luks2/luks2_keyslot_luks2.c
|
||||
lib/luks2/luks2_keyslot_reenc.c
|
||||
lib/luks2/luks2_luks1_convert.c
|
||||
lib/luks2/luks2_reencrypt.c
|
||||
lib/luks2/luks2_segment.c
|
||||
lib/luks2/luks2_token.c
|
||||
lib/luks2/luks2_token_keyring.c
|
||||
src/cryptsetup.c
|
||||
@@ -42,3 +46,4 @@ src/cryptsetup_reencrypt.c
|
||||
src/utils_tools.c
|
||||
src/utils_password.c
|
||||
src/utils_luks2.c
|
||||
src/utils_blockdev.c
|
||||
|
||||
Reference in New Issue
Block a user