qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Kevin Wolf" <kwolf@redhat.com>, "Fam Zheng" <fam@euphon.net>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	qemu-block@nongnu.org, "Markus Armbruster" <armbru@redhat.com>,
	"Max Reitz" <mreitz@redhat.com>,
	"Stefan Hajnoczi" <stefanha@redhat.com>,
	"Maxim Levitsky" <mlevitsk@redhat.com>
Subject: [Qemu-devel] [PATCH 13/13] iotests : add tests for encryption key management
Date: Wed, 14 Aug 2019 23:22:19 +0300	[thread overview]
Message-ID: <20190814202219.1870-14-mlevitsk@redhat.com> (raw)
In-Reply-To: <20190814202219.1870-1-mlevitsk@redhat.com>

Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
---
 tests/qemu-iotests/257           | 197 ++++++++++++++++++++++++++++++
 tests/qemu-iotests/257.out       |  96 +++++++++++++++
 tests/qemu-iotests/258           |  95 +++++++++++++++
 tests/qemu-iotests/258.out       |  30 +++++
 tests/qemu-iotests/259           | 199 +++++++++++++++++++++++++++++++
 tests/qemu-iotests/259.out       |   5 +
 tests/qemu-iotests/common.filter |   5 +-
 tests/qemu-iotests/group         |   3 +
 8 files changed, 628 insertions(+), 2 deletions(-)
 create mode 100755 tests/qemu-iotests/257
 create mode 100644 tests/qemu-iotests/257.out
 create mode 100755 tests/qemu-iotests/258
 create mode 100644 tests/qemu-iotests/258.out
 create mode 100644 tests/qemu-iotests/259
 create mode 100644 tests/qemu-iotests/259.out

diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257
new file mode 100755
index 0000000000..5991e4a8c7
--- /dev/null
+++ b/tests/qemu-iotests/257
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+#
+# Test encryption key management with luks
+# Based on 134
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mlevitsk@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2 luks
+_supported_proto file #TODO
+
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+
+# you are supposed to see the password as *******, see :-)
+SECRET0="--object secret,id=sec0,data=hunter0"
+SECRET1="--object secret,id=sec1,data=hunter1"
+SECRET2="--object secret,id=sec2,data=hunter2"
+SECRET3="--object secret,id=sec3,data=hunter3"
+SECRETS="$SECRET0 $SECRET1 $SECRET2 $SECRET3"
+
+
+if [ "$IMGFMT" = "qcow2" ] ; then
+	OPTPREFIX="encrypt."
+	EXTRA_IMG_ARGS="-o encrypt.format=luks"
+fi
+
+IMGSPEC0="driver=$IMGFMT,file.filename=$TEST_IMG,${OPTPREFIX}key-secret=sec0"
+IMGSPEC1="driver=$IMGFMT,file.filename=$TEST_IMG,${OPTPREFIX}key-secret=sec1"
+IMGSPEC2="driver=$IMGFMT,file.filename=$TEST_IMG,${OPTPREFIX}key-secret=sec2"
+IMGSPEC3="driver=$IMGFMT,file.filename=$TEST_IMG,${OPTPREFIX}key-secret=sec3"
+
+echo "== creating a test image =="
+_make_test_img $SECRET0 $EXTRA_IMG_ARGS -o "${OPTPREFIX}key-secret=sec0,${OPTPREFIX}iter-time=10"   32M
+
+echo
+echo "== test that key 0 opens the image =="
+$QEMU_IO $SECRET0 -c "read 0 4096" --image-opts $IMGSPEC0 | _filter_qemu_io | _filter_testdir
+
+
+echo
+echo "== adding a password to slot 1 =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec1,iter-time=10
+echo "== adding a password to slot 3 =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec3,iter-time=100,slot=3
+echo "== adding a password to slot 2 =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec2,iter-time=10
+
+echo
+echo "== all secrets should work =="
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+
+echo
+echo "== erase slot 0 and try it =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec0| _filter_img_create
+$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC0 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== erase slot 2 and try it =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef slot=2| _filter_img_create
+$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC2 | _filter_qemu_io | _filter_testdir
+
+
+# at this point slots 1 and 3 should be active
+
+echo
+echo "== filling  4 slots with secret 2 =="
+for i in $(seq 0 3) ; do
+	$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec2,iter-time=10
+done
+
+echo
+echo "== adding secret 0 =="
+	$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec0,iter-time=10
+
+echo
+echo "== adding secret 3 (last slot) =="
+	$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec3,iter-time=10
+
+echo
+echo "== trying to add another slot (should fail) =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC2 --keydef key-secret=sec3,iter-time=10
+
+echo
+echo "== all secrets should work again =="
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+echo
+echo "== erase all keys of secret 2=="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec2
+echo "== erase all keys of secret 1=="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec1
+echo "== erase all keys of secret 0=="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec0
+echo "== erase all keys of secret 3, except a remaining key =="
+
+
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec3
+
+
+echo
+echo "== only secret3 should work now  =="
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+echo
+echo "== add secret0  =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC3 --keydef key-secret=sec0,iter-time=10
+
+echo "== erase secret3 =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec3
+
+echo
+echo "== only secret0 should work now  == "
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+echo
+echo "== replace secret0 with secret1 (should fail)  =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec1,iter-time=10,slot=0
+
+echo
+echo "== replace secret0 with secret1 with force (should work)  =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec1,iter-time=10,slot=0 --force
+
+
+echo
+echo "== only secret1 should work now  =="
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+
+
+echo
+echo "== erase last secret (should fail)  =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef slot=0
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec1
+
+
+echo "== erase non existing secrets (should fail)  =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec5 --force
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef key-secret=sec0 --force
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef slot=1 --force
+
+echo
+echo "== erase last secret with force by slot (should work)  =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef slot=0 --force
+
+echo
+echo "== we have no secrets now, data is lost forever =="
+for IMGSPEC in $IMGSPEC0 $IMGSPEC1 $IMGSPEC2 $IMGSPEC3; do
+	$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
+done
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
+
diff --git a/tests/qemu-iotests/257.out b/tests/qemu-iotests/257.out
new file mode 100644
index 0000000000..77f9c9136e
--- /dev/null
+++ b/tests/qemu-iotests/257.out
@@ -0,0 +1,96 @@
+QA output created by 257
+== creating a test image ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432
+
+== test that key 0 opens the image ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== adding a password to slot 1 ==
+== adding a password to slot 3 ==
+== adding a password to slot 2 ==
+
+== all secrets should work ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== erase slot 0 and try it ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== erase slot 2 and try it ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== filling  4 slots with secret 2 ==
+
+== adding secret 0 ==
+
+== adding secret 3 (last slot) ==
+
+== trying to add another slot (should fail) ==
+qemu-img: Can't add a keyslot - all key slots are in use
+
+== all secrets should work again ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== erase all keys of secret 2==
+== erase all keys of secret 1==
+== erase all keys of secret 0==
+== erase all keys of secret 3, except a remaining key ==
+
+== only secret3 should work now  ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== add secret0  ==
+== erase secret3 ==
+
+== only secret0 should work now  ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== replace secret0 with secret1 (should fail)  ==
+qemu-img: Can't update an active key slot 0
+
+== replace secret0 with secret1 with force (should work)  ==
+
+== only secret1 should work now  ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== erase last secret (should fail)  ==
+qemu-img: Only one slot active - can't erase
+qemu-img: Only one slot active - can't erase
+== erase non existing secrets (should fail)  ==
+qemu-img: No secret with id 'sec5'
+qemu-img: Didn't erase a keyslot, because no keyslots match the given password
+
+== erase last secret with force by slot (should work)  ==
+
+== we have no secrets now, data is lost forever ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+*** done
diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258
new file mode 100755
index 0000000000..84c8ab1907
--- /dev/null
+++ b/tests/qemu-iotests/258
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+#
+# Test that encryption key managment erases the key material
+# in addition to the header
+# Based on 134
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mlevitsk@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt luks
+_supported_proto file #TODO
+
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
+
+# you are supposed to see the password as *******, see :-)
+SECRET0="--object secret,id=sec0,data=hunter0"
+SECRET1="--object secret,id=sec1,data=hunter1"
+SECRETS="$SECRET0 $SECRET1"
+
+
+IMGSPEC0="driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec0"
+IMGSPEC1="driver=$IMGFMT,file.filename=$TEST_IMG,key-secret=sec1"
+
+echo "== creating a test image =="
+_make_test_img $SECRET0 -o "key-secret=sec0,iter-time=10"   32M
+
+echo
+echo "== test that key 0 opens the image =="
+$QEMU_IO $SECRET0 -c "read 0 4096" --image-opts $IMGSPEC0 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== adding a password to slot 1 =="
+$QEMU_IMG add_encryption_key $SECRETS --image-opts $IMGSPEC0 --keydef key-secret=sec1,slot=1,iter-time=10
+
+echo
+echo "== 'backup' the image header =="
+dd if=$TEST_IMG_FILE of=${TEST_IMG_FILE}.bk bs=4K skip=0 count=1
+
+echo
+echo "== erase slot 0 =="
+$QEMU_IMG erase_encryption_key $SECRETS --image-opts $IMGSPEC1 --keydef slot=0 | _filter_img_create
+
+echo
+echo "== test that key 0 doesn't open the image =="
+$QEMU_IO $SECRET0 -c "read 0 4096" --image-opts $IMGSPEC0 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== 'restore' the image header =="
+dd if=${TEST_IMG_FILE}.bk of=${TEST_IMG_FILE} bs=4K skip=0 count=1 conv=notrunc
+
+echo
+echo "== test that key 0 still doesn't open the image (key material is erased) =="
+$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC0 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== test that key 1 still works =="
+$QEMU_IO $SECRETS -c "read 0 4096" --image-opts $IMGSPEC1 | _filter_qemu_io | _filter_testdir
+
+echo "*** done"
+rm -f $seq.full
+status=0
+
+
+exit 0
diff --git a/tests/qemu-iotests/258.out b/tests/qemu-iotests/258.out
new file mode 100644
index 0000000000..ea448a0ac1
--- /dev/null
+++ b/tests/qemu-iotests/258.out
@@ -0,0 +1,30 @@
+QA output created by 258
+== creating a test image ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432
+
+== test that key 0 opens the image ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== adding a password to slot 1 ==
+
+== 'backup' the image header ==
+1+0 records in
+1+0 records out
+
+== erase slot 0 ==
+
+== test that key 0 doesn't open the image ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== 'restore' the image header ==
+1+0 records in
+1+0 records out
+
+== test that key 0 still doesn't open the image (key material is erased) ==
+qemu-io: can't open: Invalid password, cannot unlock any keyslot
+
+== test that key 1 still works ==
+read 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/259 b/tests/qemu-iotests/259
new file mode 100644
index 0000000000..360e723a48
--- /dev/null
+++ b/tests/qemu-iotests/259
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+#
+# Test case QMP's encrypted key management
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+#
+
+import iotests
+import os
+import time
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+
+class Secret:
+    def __init__(self, index):
+        self._id = "keysec" + str(index)
+        # you are not supposed to see the password...
+        self._secret = "hunter" + str(index)
+
+    def id(self):
+        return self._id
+
+    def secret(self):
+        return self._secret
+
+    def to_cmdline_object(self):
+        return  [ "secret,id=" + self._id + ",data=" + self._secret]
+
+    def to_qmp_object(self):
+        return { "qom_type" : "secret", "id": self.id(),
+                 "props": { "data": self.secret() } }
+
+class EncryptionSetupTestCase(iotests.QMPTestCase):
+
+    # test case startup
+    def setUp(self):
+        # start the VM
+        self.vm = iotests.VM()
+        self.vm.launch()
+
+        # create the secrets and load 'em into the VM
+        self.secrets = [ Secret(i) for i in range(0, 4) ]
+        for secret in self.secrets:
+            result = self.vm.qmp("object-add", **secret.to_qmp_object())
+            self.assert_qmp(result, 'return', {})
+
+    # test case shutdown
+    def tearDown(self):
+        # stop the VM
+        self.vm.shutdown()
+
+    # create the encrypted block device
+    def createImg(self, file, secret):
+
+        if iotests.imgfmt == "qcow2":
+            prefix="encrypt."
+            extra_options = [ '-o', "encrypt.format=luks" ]
+        else:
+            prefix=""
+            extra_options = []
+
+        return iotests.qemu_img('create',
+                                '--object', *secret.to_cmdline_object(),
+                                '-f', iotests.imgfmt,
+                                '-o', prefix+'key-secret=' + secret.id(),
+                                '-o', prefix+'iter-time=10',
+                                *extra_options, file, '1M')
+
+    # open an encrypted block device
+    def openLUKS(self, id, file, secret):
+        if iotests.imgfmt == "qcow2":
+            encrypt_options = {
+                'encrypt': {
+                    'format':'luks',
+                    'key-secret' : secret.id()}
+                }
+        else:
+            encrypt_options = {
+                'key-secret' : secret.id()
+            }
+
+        return self.vm.qmp('blockdev-add', **
+            {
+                'driver': iotests.imgfmt,
+                'node-name': id,
+
+                **encrypt_options,
+
+                'file': {
+                    'driver': 'file',
+                    'filename': test_img,
+                }
+            }
+        )
+
+    # close the encrypted block device
+    def closeLUKS(self, id):
+        return self.vm.qmp('blockdev-del', **{ 'node-name': id })
+
+    # add a key to an encrypted block device
+    def addKey(self, id, secret, old_secret = None, slot = None, force = False):
+        args = {
+            'node-name': id,
+            'options' : { 'key-secret' : secret.id(), 'iter-time' : 10}
+        }
+
+        if slot != None:
+            args['options']['slot'] = slot
+        if old_secret != None:
+            args['options']['old-key-secret'] = old_secret.id()
+        if force == True:
+            args['force'] = True
+
+        return self.vm.qmp('x-blockdev-update-encryption', **args)
+
+    # erase a key from an encrypted block device
+    def eraseKey(self, id, secret = None, slot = None, force = False):
+        args = {
+            'node-name': id,
+            'options' : { }
+        }
+
+        if secret != None:
+            args['options']['key-secret'] = secret.id()
+        if slot != None:
+            args['options']['slot'] = slot
+        if force == True:
+            args['force'] = True
+
+        return self.vm.qmp('x-blockdev-erase-encryption', **args)
+
+    def check(self, result):
+        self.assert_qmp(result, 'return', {})
+
+    # create image, and change its key
+    def testChangeKey(self):
+
+        # create the image with secret0 and open it
+        result = self.createImg(test_img, self.secrets[0]);
+        self.check(self.openLUKS("testdev", test_img, self.secrets[0]))
+
+        # add key to slot 1
+        self.check(self.addKey("testdev", secret=self.secrets[1]))
+
+
+        # erase key from slot 0
+        self.check(self.eraseKey("testdev", secret=self.secrets[0]))
+
+        #reopen the image with secret1
+        self.check(self.closeLUKS("testdev"))
+        self.check(self.openLUKS("testdev", test_img, self.secrets[1]))
+
+        # close and erase the image for good
+        self.check(self.closeLUKS("testdev"))
+        os.remove(test_img)
+
+    # test that if we erase the old password,
+    # we can still change the encryption keys using 'old-secret'
+    def testOldPassword(self):
+
+        # create the image with secret0 and open it
+        result = self.createImg(test_img, self.secrets[0]);
+        self.check(self.openLUKS("testdev", test_img, self.secrets[0]))
+
+        # add key to slot 1
+        self.check(self.addKey("testdev", secret=self.secrets[1]))
+
+        # erase key from slot 0
+        self.check(self.eraseKey("testdev", secret=self.secrets[0]))
+
+        # this will fail as the old password is no longer valid
+        result = self.addKey("testdev", secret=self.secrets[2])
+        self.assert_qmp(result, 'error/desc', "Invalid password, cannot unlock any keyslot")
+
+        # this will work
+        self.check(self.addKey("testdev", secret=self.secrets[2], old_secret=self.secrets[1]))
+
+
+        # close and erase the image for good
+        self.check(self.closeLUKS("testdev"))
+        os.remove(test_img)
+
+
+if __name__ == '__main__':
+    # Encrypted formats support
+    iotests.main(iotests.main(supported_fmts=['qcow2','luks']))
diff --git a/tests/qemu-iotests/259.out b/tests/qemu-iotests/259.out
new file mode 100644
index 0000000000..fbc63e62f8
--- /dev/null
+++ b/tests/qemu-iotests/259.out
@@ -0,0 +1,5 @@
+..
+----------------------------------------------------------------------
+Ran 2 tests
+
+OK
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 35fddc746f..c0d68e8a0c 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -138,8 +138,9 @@ _filter_img_create()
         -e "s# block_state_zero=\\(on\\|off\\)##g" \
         -e "s# log_size=[0-9]\\+##g" \
         -e "s# refcount_bits=[0-9]\\+##g" \
-        -e "s# key-secret=[a-zA-Z0-9]\\+##g" \
-        -e "s# iter-time=[0-9]\\+##g" \
+        -e "s# \\(encrypt\\.\\)\\?key-secret=[a-zA-Z0-9]\\+##g" \
+        -e "s# encrypt\\.format=[a-zA-Z0-9]\\+##g" \
+        -e "s# \\(encrypt\\.\\)\\?iter-time=[0-9]\\+##g" \
         -e "s# force_size=\\(on\\|off\\)##g"
 }
 
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index f13e5f2e23..3db7f0a863 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -271,3 +271,6 @@
 254 rw backing quick
 255 rw quick
 256 rw quick
+257 rw auto
+258 rw auto quick
+259 rw auto
-- 
2.17.2



  parent reply	other threads:[~2019-08-14 20:36 UTC|newest]

Thread overview: 87+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-14 20:22 [Qemu-devel] [PATCH 00/13] RFC: luks/encrypted qcow2 key management Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 01/13] block-crypto: misc refactoring Maxim Levitsky
2019-08-20 16:38   ` Max Reitz
2019-08-22  0:05     ` Maxim Levitsky
2019-08-22 14:34       ` Max Reitz
2019-08-22 15:04         ` Maxim Levitsky
2019-08-21 15:39   ` Daniel P. Berrangé
2019-08-22  0:08     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 02/13] qcrypto-luks: " Maxim Levitsky
2019-08-15 21:40   ` [Qemu-devel] [Qemu-block] " John Snow
2019-08-19 14:21     ` Maxim Levitsky
2019-08-22 10:29     ` Daniel P. Berrangé
2019-08-22 11:04       ` Maxim Levitsky
2019-08-22 11:10         ` Daniel P. Berrangé
2019-08-22 11:13           ` Maxim Levitsky
2019-08-20 17:36   ` [Qemu-devel] " Max Reitz
2019-08-21 23:59     ` Maxim Levitsky
2019-08-22 14:32       ` Max Reitz
2019-08-25 10:46         ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 03/13] qcrypto-luks: refactoring: extract load/store/check/parse header functions Maxim Levitsky
2019-08-20 18:01   ` Max Reitz
2019-08-21 22:43     ` Maxim Levitsky
2019-08-22 10:32       ` Daniel P. Berrangé
2019-08-22 10:57         ` Maxim Levitsky
2019-08-22 10:34       ` Daniel P. Berrangé
2019-08-25 14:11         ` Maxim Levitsky
2019-08-22 10:38   ` Daniel P. Berrangé
2019-08-25 14:09     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 04/13] qcrypto-luks: refactoring: simplify the math used for keyslot locations Maxim Levitsky
2019-08-22 10:47   ` Daniel P. Berrangé
2019-08-25 14:30     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 05/13] qcrypto-luks: clear the masterkey and password before freeing them always Maxim Levitsky
2019-08-20 18:12   ` Max Reitz
2019-08-21 22:40     ` Maxim Levitsky
2019-08-22 10:49     ` Daniel P. Berrangé
2019-08-22 10:56       ` Maxim Levitsky
2019-08-25 15:31         ` Maxim Levitsky
2019-08-25 17:15           ` Maxim Levitsky
2019-08-27  8:55           ` Daniel P. Berrangé
2019-08-21 23:01   ` [Qemu-devel] [Qemu-block] " Nir Soffer
2019-08-21 23:11     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 06/13] qcrypto-luks: implement more rigorous header checking Maxim Levitsky
2019-08-22 11:04   ` Daniel P. Berrangé
2019-08-25 15:40     ` Maxim Levitsky
2019-08-25 16:08       ` Maxim Levitsky
2019-08-26 13:31         ` Eric Blake
2019-08-26 13:39           ` Maxim Levitsky
2019-08-27  8:56         ` Daniel P. Berrangé
2019-08-14 20:22 ` [Qemu-devel] [PATCH 07/13] block: add manage-encryption command (qmp and blockdev) Maxim Levitsky
2019-08-20 18:27   ` Max Reitz
2019-08-21 22:32     ` Maxim Levitsky
2019-08-22 11:14     ` Daniel P. Berrangé
2019-08-21 11:47   ` Markus Armbruster
2019-08-21 22:24     ` Maxim Levitsky
2019-08-22 14:07       ` Markus Armbruster
2019-08-25 16:42         ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 08/13] qcrypto: add the plumbing for encryption management Maxim Levitsky
2019-08-22 11:16   ` Daniel P. Berrangé
2019-08-22 11:47     ` Maxim Levitsky
2019-08-22 11:49       ` Daniel P. Berrangé
2019-08-14 20:22 ` [Qemu-devel] [PATCH 09/13] qcrypto-luks: implement the encryption key management Maxim Levitsky
2019-08-22 11:27   ` Daniel P. Berrangé
2019-08-25 17:01     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 10/13] block/crypto: " Maxim Levitsky
2019-08-22 11:29   ` Daniel P. Berrangé
2019-08-22 11:36     ` Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 11/13] block/qcow2: implement the encryption key managment Maxim Levitsky
2019-08-14 20:22 ` [Qemu-devel] [PATCH 12/13] qemu-img: implement key management Maxim Levitsky
2019-08-20 18:29   ` Max Reitz
2019-08-21 22:33     ` Maxim Levitsky
2019-08-22 11:32     ` Daniel P. Berrangé
2019-08-22 14:42       ` Max Reitz
2019-08-25 17:04         ` Maxim Levitsky
2019-08-14 20:22 ` Maxim Levitsky [this message]
2019-08-14 21:08 ` [Qemu-devel] [PATCH 00/13] RFC: luks/encrypted qcow2 " Eric Blake
2019-08-15  8:49   ` Maxim Levitsky
2019-08-15  9:10   ` Kevin Wolf
2019-08-15 14:18     ` Markus Armbruster
2019-08-15 14:44       ` Maxim Levitsky
2019-08-15 15:00         ` Eric Blake
2019-08-19 12:35           ` Maxim Levitsky
2019-08-21 11:31             ` Markus Armbruster
2019-08-21 13:22               ` Maxim Levitsky
2019-08-20 17:59 ` Max Reitz
2019-08-21 22:00   ` Maxim Levitsky
2019-08-22 11:35 ` Daniel P. Berrangé
2019-08-25 17:10   ` Maxim Levitsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190814202219.1870-14-mlevitsk@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=fam@euphon.net \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).