From: Vojtech Trefny <vtrefny@redhat.com>
Date: Tue, 12 Mar 2019 09:28:05 +0100
Subject: Use existing cryptsetup API for changing keyslot passphrase

Instead of manually removing the keyslot and adding new a one.
Our old code also doesn't work in FIPS mode.

(cherry picked from commit 34ed7becf4536ee1277175abdf47c075f340af61)
---
 src/plugins/crypto.c | 40 +++++++++-------------------------------
 tests/crypto_test.py |  3 +++
 2 files changed, 12 insertions(+), 31 deletions(-)

diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c
index 6b5be9d..205499f 100644
--- a/src/plugins/crypto.c
+++ b/src/plugins/crypto.c
@@ -1359,8 +1359,6 @@ gboolean bd_crypto_luks_remove_key (const gchar *device, const gchar *pass, cons
 gboolean bd_crypto_luks_change_key_blob (const gchar *device, const guint8 *pass_data, gsize data_len, const guint8 *npass_data, gsize ndata_len, GError **error) {
     struct crypt_device *cd = NULL;
     gint ret = 0;
-    gchar *volume_key = NULL;
-    gsize vk_size = 0;
     guint64 progress_id = 0;
     gchar *msg = NULL;
 
@@ -1385,41 +1383,21 @@ gboolean bd_crypto_luks_change_key_blob (const gchar *device, const guint8 *pass
         return FALSE;
     }
 
-    vk_size = crypt_get_volume_key_size(cd);
-    volume_key = (gchar *) g_malloc (vk_size);
-
-    ret = crypt_volume_key_get (cd, CRYPT_ANY_SLOT, volume_key, &vk_size, (char*) pass_data, data_len);
-    if (ret < 0) {
-        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
-                     "Failed to load device's volume key: %s", strerror_l(-ret, c_locale));
-        crypt_free (cd);
-        g_free (volume_key);
-        bd_utils_report_finished (progress_id, (*error)->message);
-        return FALSE;
-    }
-
-    /* ret is the number of the slot with the given pass */
-    ret = crypt_keyslot_destroy (cd, ret);
-    if (ret != 0) {
-        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_REMOVE_KEY,
-                     "Failed to remove the old passphrase: %s", strerror_l(-ret, c_locale));
-        crypt_free (cd);
-        g_free (volume_key);
-        bd_utils_report_finished (progress_id, (*error)->message);
-        return FALSE;
-    }
-
-    ret = crypt_keyslot_add_by_volume_key (cd, ret, volume_key, vk_size, (char*) npass_data, ndata_len);
+    ret = crypt_keyslot_change_by_passphrase (cd, CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
+                                              (char*) pass_data, data_len,
+                                              (char*) npass_data, ndata_len);
     if (ret < 0) {
-        g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
-                     "Failed to add the new passphrase: %s", strerror_l(-ret, c_locale));
+        if (ret == -EPERM)
+            g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
+                         "Failed to change the passphrase: No keyslot with given passphrase found.");
+        else
+            g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
+                         "Failed to change the passphrase: %s", strerror_l (-ret, c_locale));
         crypt_free (cd);
-        g_free (volume_key);
         bd_utils_report_finished (progress_id, (*error)->message);
         return FALSE;
     }
 
-    g_free (volume_key);
     crypt_free (cd);
     bd_utils_report_finished (progress_id, "Completed");
     return TRUE;
diff --git a/tests/crypto_test.py b/tests/crypto_test.py
index c048570..747b702 100644
--- a/tests/crypto_test.py
+++ b/tests/crypto_test.py
@@ -401,6 +401,9 @@ class CryptoTestChangeKey(CryptoTestCase):
         succ = create_fn(self.loop_dev, PASSWD, None)
         self.assertTrue(succ)
 
+        with six.assertRaisesRegex(self, GLib.GError, r"No keyslot with given passphrase found."):
+            BlockDev.crypto_luks_change_key(self.loop_dev, "wrong-passphrase", PASSWD2)
+
         succ = BlockDev.crypto_luks_change_key(self.loop_dev, PASSWD, PASSWD2)
         self.assertTrue(succ)
 
