From: Milan Broz Date: Fri, 7 Dec 2012 14:29:44 +0000 (+0100) Subject: Move change key into library (add crypt_keyslot_change_by_passphrase). X-Git-Tag: upstream/1.6~122 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Fcryptsetup.git;a=commitdiff_plain;h=05af3a3383aea6bdd5050b6c5207ac3a55a3f05b 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. --- diff --git a/TODO b/TODO index fbccb0a..e813729 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 04c53fb..54bcbff 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -599,6 +599,33 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd, 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 * * @pre @e cd contains initialized and formatted LUKS device context diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 801add6..27c5cb4 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -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; diff --git a/lib/setup.c b/lib/setup.c index 995e20d..992f3c4 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -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, diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 6fb3f8e..d652bad 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -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; - 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")); + /* 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; - } - - 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; }