Move change key into library (add crypt_keyslot_change_by_passphrase).

This change is useful mainly in FIPS mode, where we cannot
extract volume key directly from libcryptsetup.
This commit is contained in:
Milan Broz
2012-12-07 15:29:44 +01:00
parent 16c82312f3
commit 05af3a3383
5 changed files with 101 additions and 66 deletions

3
TODO
View File

@@ -1,7 +1,4 @@
Version 1.6.0:
- Export wipe device functions
- Support K/M suffixes for align payload (new switch?).
- FIPS: move changekey to library
- online reencryption api?
- integrate more metadata formats
- TRIM for keyslots

View File

@@ -598,6 +598,33 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
const char *new_passphrase,
size_t new_passphrase_size);
/**
* Change defined key slot using provided passphrase
*
* @pre @e cd contains initialized and formatted LUKS device context
*
* @param cd crypt device handle
* @param keyslot_old old keyslot or @e CRYPT_ANY_SLOT
* @param keyslot_new new keyslot (can be the same as old)
* @param passphrase passphrase used to unlock volume key, @e NULL for query
* @param passphrase_size size of passphrase (binary data)
* @param new_passphrase passphrase for new keyslot, @e NULL for query
* @param new_passphrase_size size of @e new_passphrase (binary data)
*
* @return allocated key slot number or negative errno otherwise.
*
* @note This function is just internal implementation of luksChange
* command to avoid reading of volume key outside libcryptsetup boundary
* in FIPS mode.
*/
int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
const char *new_passphrase,
size_t new_passphrase_size);
/**
* Add key slot using provided key file path
*

View File

@@ -26,6 +26,7 @@ CRYPTSETUP_1.0 {
crypt_free;
crypt_keyslot_add_by_passphrase;
crypt_keyslot_change_by_passphrase;
crypt_keyslot_add_by_keyfile;
crypt_keyslot_add_by_keyfile_offset;
crypt_keyslot_add_by_volume_key;

View File

@@ -1649,6 +1649,67 @@ out:
return r ?: keyslot;
}
int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
int keyslot_old,
int keyslot_new,
const char *passphrase,
size_t passphrase_size,
const char *new_passphrase,
size_t new_passphrase_size)
{
struct volume_key *vk = NULL;
int r = -EINVAL;
log_dbg("Changing passphrase from old keyslot %d to new %d.",
keyslot_old, keyslot_new);
if (!isLUKS(cd->type)) {
log_err(cd, _("This operation is supported only for LUKS device.\n"));
return -EINVAL;
}
r = LUKS_open_key_with_hdr(keyslot_old, passphrase, passphrase_size,
&cd->u.luks1.hdr, &vk, cd);
if (r < 0)
return r;
if (keyslot_old != CRYPT_ANY_SLOT && keyslot_old != r) {
log_dbg("Keyslot mismatch.");
goto out;
}
keyslot_old = r;
if (keyslot_new == CRYPT_ANY_SLOT) {
keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
if (keyslot_new < 0)
keyslot_new = keyslot_old;
}
if (keyslot_old == keyslot_new) {
log_dbg("Key slot %d is going to be overwritten.", keyslot_old);
(void)crypt_keyslot_destroy(cd, keyslot_old);
}
r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size,
&cd->u.luks1.hdr, vk, cd->iteration_time,
&cd->u.luks1.PBKDF2_per_sec, cd);
if (keyslot_old == keyslot_new) {
if (r >= 0)
log_verbose(cd, _("Key slot %d changed.\n"), r);
} else {
if (r >= 0) {
log_verbose(cd, _("Replaced with key slot %d.\n"), r);
r = crypt_keyslot_destroy(cd, keyslot_old);
}
}
if (r < 0)
log_err(cd, _("Failed to swap new key slot.\n"));
out:
crypt_free_volume_key(vk);
return r ?: keyslot_new;
}
int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
int keyslot,
const char *keyfile,

View File

@@ -909,24 +909,13 @@ out:
return r;
}
static int _slots_full(struct crypt_device *cd)
{
int i;
for (i = 0; i < crypt_keyslot_max(crypt_get_type(cd)); i++)
if (crypt_keyslot_status(cd, i) == CRYPT_SLOT_INACTIVE)
return 0;
return 1;
}
static int action_luksChangeKey(void)
{
const char *opt_new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
struct crypt_device *cd = NULL;
char *vk = NULL, *password = NULL;
size_t passwordLen = 0;
size_t vk_size;
int new_key_slot, old_key_slot, r;
char *password = NULL, *password_new = NULL;
size_t password_size = 0, password_new_size = 0;
int r;
if ((r = crypt_init(&cd, uuid_or_device(action_argv[0]))))
goto out;
@@ -938,71 +927,31 @@ static int action_luksChangeKey(void)
crypt_set_iteration_time(cd, opt_iteration_time);
r = crypt_get_key(_("Enter LUKS passphrase to be changed: "),
&password, &passwordLen,
&password, &password_size,
opt_keyfile_offset, opt_keyfile_size, opt_key_file,
opt_timeout, _verify_passphrase(0), cd);
if (r < 0)
goto out;
vk_size = crypt_get_volume_key_size(cd);
vk = crypt_safe_alloc(vk_size);
if (!vk) {
r = -ENOMEM;
/* Check password before asking for new one */
r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot,
password, password_size, 0);
if (r < 0)
goto out;
}
r = crypt_volume_key_get(cd, opt_key_slot, vk, &vk_size,
password, passwordLen);
if (r < 0) {
if (opt_key_slot != CRYPT_ANY_SLOT)
log_err(_("No key available with this passphrase.\n"));
goto out;
}
if (opt_key_slot != CRYPT_ANY_SLOT || _slots_full(cd)) {
log_dbg("Key slot %d is going to be overwritten (%s).",
r, opt_key_slot != CRYPT_ANY_SLOT ?
"explicit key slot specified" : "no free key slot");
old_key_slot = r;
new_key_slot = r;
} else {
log_dbg("Allocating new key slot.");
old_key_slot = r;
new_key_slot = CRYPT_ANY_SLOT;
}
crypt_safe_free(password);
password = NULL;
passwordLen = 0;
r = crypt_get_key(_("Enter new LUKS passphrase: "),
&password, &passwordLen,
&password_new, &password_new_size,
opt_new_keyfile_offset, opt_new_keyfile_size,
opt_new_key_file,
opt_timeout, _verify_passphrase(0), cd);
if (r < 0)
goto out;
if (new_key_slot == old_key_slot) {
(void)crypt_keyslot_destroy(cd, old_key_slot);
r = crypt_keyslot_add_by_volume_key(cd, new_key_slot,
vk, vk_size,
password, passwordLen);
if (r >= 0)
log_verbose(_("Key slot %d changed.\n"), r);
} else {
r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT,
vk, vk_size,
password, passwordLen);
if (r >= 0) {
log_verbose(_("Replaced with key slot %d.\n"), r);
r = crypt_keyslot_destroy(cd, old_key_slot);
}
}
if (r < 0)
log_err(_("Failed to swap new key slot.\n"));
r = crypt_keyslot_change_by_passphrase(cd, opt_key_slot, opt_key_slot,
password, password_size, password_new, password_new_size);
out:
crypt_safe_free(vk);
crypt_safe_free(password);
crypt_safe_free(password_new);
crypt_free(cd);
return r;
}