17c477526SPhilippe Mathieu-Daudé#!/usr/bin/env python3 29dd003a9SVladimir Sementsov-Ogievskiy# group: rw sudo 36278ae03SDaniel P. Berrange# 46278ae03SDaniel P. Berrange# Copyright (C) 2016 Red Hat, Inc. 56278ae03SDaniel P. Berrange# 66278ae03SDaniel P. Berrange# This program is free software; you can redistribute it and/or modify 76278ae03SDaniel P. Berrange# it under the terms of the GNU General Public License as published by 86278ae03SDaniel P. Berrange# the Free Software Foundation; either version 2 of the License, or 96278ae03SDaniel P. Berrange# (at your option) any later version. 106278ae03SDaniel P. Berrange# 116278ae03SDaniel P. Berrange# This program is distributed in the hope that it will be useful, 126278ae03SDaniel P. Berrange# but WITHOUT ANY WARRANTY; without even the implied warranty of 136278ae03SDaniel P. Berrange# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 146278ae03SDaniel P. Berrange# GNU General Public License for more details. 156278ae03SDaniel P. Berrange# 166278ae03SDaniel P. Berrange# You should have received a copy of the GNU General Public License 176278ae03SDaniel P. Berrange# along with this program. If not, see <http://www.gnu.org/licenses/>. 186278ae03SDaniel P. Berrange# 196278ae03SDaniel P. Berrange# Creator/Owner: Daniel P. Berrange <berrange@redhat.com> 206278ae03SDaniel P. Berrange# 216278ae03SDaniel P. Berrange# Exercise the QEMU 'luks' block driver to validate interoperability 226278ae03SDaniel P. Berrange# with the Linux dm-crypt + cryptsetup implementation 236278ae03SDaniel P. Berrange 246278ae03SDaniel P. Berrangeimport subprocess 256278ae03SDaniel P. Berrangeimport os 266278ae03SDaniel P. Berrangeimport os.path 276278ae03SDaniel P. Berrange 286278ae03SDaniel P. Berrangeimport base64 296278ae03SDaniel P. Berrange 306278ae03SDaniel P. Berrangeimport iotests 316278ae03SDaniel P. Berrange 326278ae03SDaniel P. Berrange 336278ae03SDaniel P. Berrangeclass LUKSConfig(object): 346278ae03SDaniel P. Berrange """Represent configuration parameters for a single LUKS 356278ae03SDaniel P. Berrange setup to be tested""" 366278ae03SDaniel P. Berrange 376278ae03SDaniel P. Berrange def __init__(self, name, cipher, keylen, mode, ivgen, 386278ae03SDaniel P. Berrange ivgen_hash, hash, password=None, passwords=None): 396278ae03SDaniel P. Berrange 406278ae03SDaniel P. Berrange self.name = name 416278ae03SDaniel P. Berrange self.cipher = cipher 426278ae03SDaniel P. Berrange self.keylen = keylen 436278ae03SDaniel P. Berrange self.mode = mode 446278ae03SDaniel P. Berrange self.ivgen = ivgen 456278ae03SDaniel P. Berrange self.ivgen_hash = ivgen_hash 466278ae03SDaniel P. Berrange self.hash = hash 476278ae03SDaniel P. Berrange 486278ae03SDaniel P. Berrange if passwords is not None: 496278ae03SDaniel P. Berrange self.passwords = passwords 506278ae03SDaniel P. Berrange else: 516278ae03SDaniel P. Berrange self.passwords = {} 526278ae03SDaniel P. Berrange 536278ae03SDaniel P. Berrange if password is None: 546278ae03SDaniel P. Berrange self.passwords["0"] = "123456" 556278ae03SDaniel P. Berrange else: 566278ae03SDaniel P. Berrange self.passwords["0"] = password 576278ae03SDaniel P. Berrange 586278ae03SDaniel P. Berrange def __repr__(self): 596278ae03SDaniel P. Berrange return self.name 606278ae03SDaniel P. Berrange 616278ae03SDaniel P. Berrange def image_name(self): 626278ae03SDaniel P. Berrange return "luks-%s.img" % self.name 636278ae03SDaniel P. Berrange 646278ae03SDaniel P. Berrange def image_path(self): 656278ae03SDaniel P. Berrange return os.path.join(iotests.test_dir, self.image_name()) 666278ae03SDaniel P. Berrange 676278ae03SDaniel P. Berrange def device_name(self): 686278ae03SDaniel P. Berrange return "qiotest-145-%s" % self.name 696278ae03SDaniel P. Berrange 706278ae03SDaniel P. Berrange def device_path(self): 716278ae03SDaniel P. Berrange return "/dev/mapper/" + self.device_name() 726278ae03SDaniel P. Berrange 736278ae03SDaniel P. Berrange def first_password(self): 746278ae03SDaniel P. Berrange for i in range(8): 756278ae03SDaniel P. Berrange slot = str(i) 766278ae03SDaniel P. Berrange if slot in self.passwords: 776278ae03SDaniel P. Berrange return (self.passwords[slot], slot) 786278ae03SDaniel P. Berrange raise Exception("No password found") 796278ae03SDaniel P. Berrange 806278ae03SDaniel P. Berrange def first_password_base64(self): 816278ae03SDaniel P. Berrange (pw, slot) = self.first_password() 828eb5e674SMax Reitz return base64.b64encode(pw.encode('ascii')).decode('ascii') 836278ae03SDaniel P. Berrange 846278ae03SDaniel P. Berrange def active_slots(self): 856278ae03SDaniel P. Berrange slots = [] 866278ae03SDaniel P. Berrange for i in range(8): 876278ae03SDaniel P. Berrange slot = str(i) 886278ae03SDaniel P. Berrange if slot in self.passwords: 896278ae03SDaniel P. Berrange slots.append(slot) 906278ae03SDaniel P. Berrange return slots 916278ae03SDaniel P. Berrange 926278ae03SDaniel P. Berrangedef verify_passwordless_sudo(): 936278ae03SDaniel P. Berrange """Check whether sudo is configured to allow 946278ae03SDaniel P. Berrange password-less access to commands""" 956278ae03SDaniel P. Berrange 966278ae03SDaniel P. Berrange args = ["sudo", "-n", "/bin/true"] 976278ae03SDaniel P. Berrange 986278ae03SDaniel P. Berrange proc = subprocess.Popen(args, 996278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 1006278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 1018eb5e674SMax Reitz stderr=subprocess.STDOUT, 1028eb5e674SMax Reitz universal_newlines=True) 1036278ae03SDaniel P. Berrange 1046278ae03SDaniel P. Berrange msg = proc.communicate()[0] 1056278ae03SDaniel P. Berrange 1066278ae03SDaniel P. Berrange if proc.returncode != 0: 1076278ae03SDaniel P. Berrange iotests.notrun('requires password-less sudo access: %s' % msg) 1086278ae03SDaniel P. Berrange 1096278ae03SDaniel P. Berrange 1106278ae03SDaniel P. Berrangedef cryptsetup(args, password=None): 1116278ae03SDaniel P. Berrange """Run the cryptsetup command in batch mode""" 1126278ae03SDaniel P. Berrange 1136278ae03SDaniel P. Berrange fullargs = ["sudo", "cryptsetup", "-q", "-v"] 1146278ae03SDaniel P. Berrange fullargs.extend(args) 1156278ae03SDaniel P. Berrange 1166278ae03SDaniel P. Berrange iotests.log(" ".join(fullargs), filters=[iotests.filter_test_dir]) 1176278ae03SDaniel P. Berrange proc = subprocess.Popen(fullargs, 1186278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 1196278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 1208eb5e674SMax Reitz stderr=subprocess.STDOUT, 1218eb5e674SMax Reitz universal_newlines=True) 1226278ae03SDaniel P. Berrange 1236278ae03SDaniel P. Berrange msg = proc.communicate(password)[0] 1246278ae03SDaniel P. Berrange 1256278ae03SDaniel P. Berrange if proc.returncode != 0: 1266278ae03SDaniel P. Berrange raise Exception(msg) 1276278ae03SDaniel P. Berrange 1286278ae03SDaniel P. Berrange 1296278ae03SDaniel P. Berrangedef cryptsetup_add_password(config, slot): 1306278ae03SDaniel P. Berrange """Add another password to a LUKS key slot""" 1316278ae03SDaniel P. Berrange 1326278ae03SDaniel P. Berrange (password, mainslot) = config.first_password() 1336278ae03SDaniel P. Berrange 1346278ae03SDaniel P. Berrange pwfile = os.path.join(iotests.test_dir, "passwd.txt") 1356278ae03SDaniel P. Berrange with open(pwfile, "w") as fh: 1366278ae03SDaniel P. Berrange fh.write(config.passwords[slot]) 1376278ae03SDaniel P. Berrange 1386278ae03SDaniel P. Berrange try: 1396278ae03SDaniel P. Berrange args = ["luksAddKey", config.image_path(), 1406278ae03SDaniel P. Berrange "--key-slot", slot, 1416278ae03SDaniel P. Berrange "--key-file", "-", 142307d9991SDaniel P. Berrange "--iter-time", "10", 1436278ae03SDaniel P. Berrange pwfile] 1446278ae03SDaniel P. Berrange 1456278ae03SDaniel P. Berrange cryptsetup(args, password) 1466278ae03SDaniel P. Berrange finally: 1476278ae03SDaniel P. Berrange os.unlink(pwfile) 1486278ae03SDaniel P. Berrange 1496278ae03SDaniel P. Berrange 1506278ae03SDaniel P. Berrangedef cryptsetup_format(config): 1516278ae03SDaniel P. Berrange """Format a new LUKS volume with cryptsetup, adding the 1526278ae03SDaniel P. Berrange first key slot only""" 1536278ae03SDaniel P. Berrange 1546278ae03SDaniel P. Berrange (password, slot) = config.first_password() 1556278ae03SDaniel P. Berrange 156da51e998SDaniel P. Berrangé args = ["luksFormat", "--type", "luks1"] 1576278ae03SDaniel P. Berrange cipher = config.cipher + "-" + config.mode + "-" + config.ivgen 1586278ae03SDaniel P. Berrange if config.ivgen_hash is not None: 1596278ae03SDaniel P. Berrange cipher = cipher + ":" + config.ivgen_hash 1608b7cdba3SDaniel P. Berrange elif config.ivgen == "essiv": 1618b7cdba3SDaniel P. Berrange cipher = cipher + ":" + "sha256" 1626278ae03SDaniel P. Berrange args.extend(["--cipher", cipher]) 1636278ae03SDaniel P. Berrange if config.mode == "xts": 1646278ae03SDaniel P. Berrange args.extend(["--key-size", str(config.keylen * 2)]) 1656278ae03SDaniel P. Berrange else: 1666278ae03SDaniel P. Berrange args.extend(["--key-size", str(config.keylen)]) 1676278ae03SDaniel P. Berrange if config.hash is not None: 1686278ae03SDaniel P. Berrange args.extend(["--hash", config.hash]) 1696278ae03SDaniel P. Berrange args.extend(["--key-slot", slot]) 1706278ae03SDaniel P. Berrange args.extend(["--key-file", "-"]) 171307d9991SDaniel P. Berrange args.extend(["--iter-time", "10"]) 1726278ae03SDaniel P. Berrange args.append(config.image_path()) 1736278ae03SDaniel P. Berrange 1746278ae03SDaniel P. Berrange cryptsetup(args, password) 1756278ae03SDaniel P. Berrange 1766278ae03SDaniel P. Berrange 1776278ae03SDaniel P. Berrangedef chown(config): 1786278ae03SDaniel P. Berrange """Set the ownership of a open LUKS device to this user""" 1796278ae03SDaniel P. Berrange 1806278ae03SDaniel P. Berrange path = config.device_path() 1816278ae03SDaniel P. Berrange 1826278ae03SDaniel P. Berrange args = ["sudo", "chown", "%d:%d" % (os.getuid(), os.getgid()), path] 1836278ae03SDaniel P. Berrange iotests.log(" ".join(args), filters=[iotests.filter_chown]) 1846278ae03SDaniel P. Berrange proc = subprocess.Popen(args, 1856278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 1866278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 1876278ae03SDaniel P. Berrange stderr=subprocess.STDOUT) 1886278ae03SDaniel P. Berrange 1896278ae03SDaniel P. Berrange msg = proc.communicate()[0] 1906278ae03SDaniel P. Berrange 1916278ae03SDaniel P. Berrange if proc.returncode != 0: 192ae50b71dSDaniel P. Berrange raise Exception(msg) 1936278ae03SDaniel P. Berrange 1946278ae03SDaniel P. Berrange 1956278ae03SDaniel P. Berrangedef cryptsetup_open(config): 1966278ae03SDaniel P. Berrange """Open an image as a LUKS device""" 1976278ae03SDaniel P. Berrange 1986278ae03SDaniel P. Berrange (password, slot) = config.first_password() 1996278ae03SDaniel P. Berrange 2006278ae03SDaniel P. Berrange args = ["luksOpen", config.image_path(), config.device_name()] 2016278ae03SDaniel P. Berrange 2026278ae03SDaniel P. Berrange cryptsetup(args, password) 2036278ae03SDaniel P. Berrange 2046278ae03SDaniel P. Berrange 2056278ae03SDaniel P. Berrangedef cryptsetup_close(config): 2066278ae03SDaniel P. Berrange """Close an active LUKS device """ 2076278ae03SDaniel P. Berrange 2086278ae03SDaniel P. Berrange args = ["luksClose", config.device_name()] 2096278ae03SDaniel P. Berrange cryptsetup(args) 2106278ae03SDaniel P. Berrange 2116278ae03SDaniel P. Berrange 2126278ae03SDaniel P. Berrangedef delete_image(config): 2136278ae03SDaniel P. Berrange """Delete a disk image""" 2146278ae03SDaniel P. Berrange 2156278ae03SDaniel P. Berrange try: 2166278ae03SDaniel P. Berrange os.unlink(config.image_path()) 2176278ae03SDaniel P. Berrange iotests.log("unlink %s" % config.image_path(), 2186278ae03SDaniel P. Berrange filters=[iotests.filter_test_dir]) 2196278ae03SDaniel P. Berrange except Exception as e: 2206278ae03SDaniel P. Berrange pass 2216278ae03SDaniel P. Berrange 2226278ae03SDaniel P. Berrange 2236278ae03SDaniel P. Berrangedef create_image(config, size_mb): 2246278ae03SDaniel P. Berrange """Create a bare disk image with requested size""" 2256278ae03SDaniel P. Berrange 2266278ae03SDaniel P. Berrange delete_image(config) 2276278ae03SDaniel P. Berrange iotests.log("truncate %s --size %dMB" % (config.image_path(), size_mb), 2286278ae03SDaniel P. Berrange filters=[iotests.filter_test_dir]) 2296278ae03SDaniel P. Berrange with open(config.image_path(), "w") as fn: 2306278ae03SDaniel P. Berrange fn.truncate(size_mb * 1024 * 1024) 2316278ae03SDaniel P. Berrange 2326278ae03SDaniel P. Berrange 233*4dd218fdSHanna Reitzdef check_cipher_support(config, output): 234*4dd218fdSHanna Reitz """Check the output of qemu-img or qemu-io for mention of the respective 235*4dd218fdSHanna Reitz cipher algorithm being unsupported, and if so, skip this test. 236*4dd218fdSHanna Reitz (Returns `output` for convenience.)""" 237*4dd218fdSHanna Reitz 238*4dd218fdSHanna Reitz if 'Unsupported cipher algorithm' in output: 239*4dd218fdSHanna Reitz iotests.notrun('Unsupported cipher algorithm ' 240*4dd218fdSHanna Reitz f'{config.cipher}-{config.keylen}-{config.mode}; ' 241*4dd218fdSHanna Reitz 'consider configuring qemu with a different crypto ' 242*4dd218fdSHanna Reitz 'backend') 243*4dd218fdSHanna Reitz return output 244*4dd218fdSHanna Reitz 2456278ae03SDaniel P. Berrangedef qemu_img_create(config, size_mb): 2466278ae03SDaniel P. Berrange """Create and format a disk image with LUKS using qemu-img""" 2476278ae03SDaniel P. Berrange 2486278ae03SDaniel P. Berrange opts = [ 2496278ae03SDaniel P. Berrange "key-secret=sec0", 250307d9991SDaniel P. Berrange "iter-time=10", 2516278ae03SDaniel P. Berrange "cipher-alg=%s-%d" % (config.cipher, config.keylen), 2526278ae03SDaniel P. Berrange "cipher-mode=%s" % config.mode, 2536278ae03SDaniel P. Berrange "ivgen-alg=%s" % config.ivgen, 2546278ae03SDaniel P. Berrange "hash-alg=%s" % config.hash, 2556278ae03SDaniel P. Berrange ] 2566278ae03SDaniel P. Berrange if config.ivgen_hash is not None: 2576278ae03SDaniel P. Berrange opts.append("ivgen-hash-alg=%s" % config.ivgen_hash) 2586278ae03SDaniel P. Berrange 2596278ae03SDaniel P. Berrange args = ["create", "-f", "luks", 2606278ae03SDaniel P. Berrange "--object", 2616278ae03SDaniel P. Berrange ("secret,id=sec0,data=%s,format=base64" % 2626278ae03SDaniel P. Berrange config.first_password_base64()), 2636278ae03SDaniel P. Berrange "-o", ",".join(opts), 2646278ae03SDaniel P. Berrange config.image_path(), 2656278ae03SDaniel P. Berrange "%dM" % size_mb] 2666278ae03SDaniel P. Berrange 2676278ae03SDaniel P. Berrange iotests.log("qemu-img " + " ".join(args), filters=[iotests.filter_test_dir]) 268*4dd218fdSHanna Reitz iotests.log(check_cipher_support(config, iotests.qemu_img_pipe(*args)), 269*4dd218fdSHanna Reitz filters=[iotests.filter_test_dir]) 2706278ae03SDaniel P. Berrange 2716278ae03SDaniel P. Berrangedef qemu_io_image_args(config, dev=False): 2726278ae03SDaniel P. Berrange """Get the args for access an image or device with qemu-io""" 2736278ae03SDaniel P. Berrange 2746278ae03SDaniel P. Berrange if dev: 2756278ae03SDaniel P. Berrange return [ 2766278ae03SDaniel P. Berrange "--image-opts", 2774e04f3d9SKevin Wolf "driver=host_device,filename=%s" % config.device_path()] 2786278ae03SDaniel P. Berrange else: 2796278ae03SDaniel P. Berrange return [ 2806278ae03SDaniel P. Berrange "--object", 2816278ae03SDaniel P. Berrange ("secret,id=sec0,data=%s,format=base64" % 2826278ae03SDaniel P. Berrange config.first_password_base64()), 2836278ae03SDaniel P. Berrange "--image-opts", 2846278ae03SDaniel P. Berrange ("driver=luks,key-secret=sec0,file.filename=%s" % 2856278ae03SDaniel P. Berrange config.image_path())] 2866278ae03SDaniel P. Berrange 2876278ae03SDaniel P. Berrangedef qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): 2886278ae03SDaniel P. Berrange """Write a pattern of data to a LUKS image or device""" 2896278ae03SDaniel P. Berrange 290ae50b71dSDaniel P. Berrange if dev: 291ae50b71dSDaniel P. Berrange chown(config) 2926278ae03SDaniel P. Berrange args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 2936278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 2946278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 295*4dd218fdSHanna Reitz iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), 296*4dd218fdSHanna Reitz filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) 2976278ae03SDaniel P. Berrange 2986278ae03SDaniel P. Berrange 2996278ae03SDaniel P. Berrangedef qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): 3006278ae03SDaniel P. Berrange """Read a pattern of data to a LUKS image or device""" 3016278ae03SDaniel P. Berrange 302ae50b71dSDaniel P. Berrange if dev: 303ae50b71dSDaniel P. Berrange chown(config) 3046278ae03SDaniel P. Berrange args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 3056278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 3066278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 307*4dd218fdSHanna Reitz iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), 308*4dd218fdSHanna Reitz filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) 3096278ae03SDaniel P. Berrange 3106278ae03SDaniel P. Berrange 3116278ae03SDaniel P. Berrangedef test_once(config, qemu_img=False): 3126278ae03SDaniel P. Berrange """Run the test with a desired LUKS configuration. Can either 3136278ae03SDaniel P. Berrange use qemu-img for creating the initial volume, or cryptsetup, 3146278ae03SDaniel P. Berrange in order to test interoperability in both directions""" 3156278ae03SDaniel P. Berrange 3166278ae03SDaniel P. Berrange iotests.log("# ================= %s %s =================" % ( 3176278ae03SDaniel P. Berrange "qemu-img" if qemu_img else "dm-crypt", config)) 3186278ae03SDaniel P. Berrange 3196278ae03SDaniel P. Berrange oneKB = 1024 3206278ae03SDaniel P. Berrange oneMB = oneKB * 1024 3216278ae03SDaniel P. Berrange oneGB = oneMB * 1024 3226278ae03SDaniel P. Berrange oneTB = oneGB * 1024 3236278ae03SDaniel P. Berrange 3246278ae03SDaniel P. Berrange # 4 TB, so that we pass the 32-bit sector number boundary. 3256278ae03SDaniel P. Berrange # Important for testing correctness of some IV generators 3266278ae03SDaniel P. Berrange # The files are sparse, so not actually using this much space 3276278ae03SDaniel P. Berrange image_size = 4 * oneTB 3286278ae03SDaniel P. Berrange if qemu_img: 3296278ae03SDaniel P. Berrange iotests.log("# Create image") 3309a3a9a63SMax Reitz qemu_img_create(config, image_size // oneMB) 3316278ae03SDaniel P. Berrange else: 3326278ae03SDaniel P. Berrange iotests.log("# Create image") 3339a3a9a63SMax Reitz create_image(config, image_size // oneMB) 3346278ae03SDaniel P. Berrange 3356278ae03SDaniel P. Berrange lowOffsetMB = 100 3369a3a9a63SMax Reitz highOffsetMB = 3 * oneTB // oneMB 3376278ae03SDaniel P. Berrange 3386278ae03SDaniel P. Berrange try: 3396278ae03SDaniel P. Berrange if not qemu_img: 3406278ae03SDaniel P. Berrange iotests.log("# Format image") 3416278ae03SDaniel P. Berrange cryptsetup_format(config) 3426278ae03SDaniel P. Berrange 3436278ae03SDaniel P. Berrange for slot in config.active_slots()[1:]: 3446278ae03SDaniel P. Berrange iotests.log("# Add password slot %s" % slot) 3456278ae03SDaniel P. Berrange cryptsetup_add_password(config, slot) 3466278ae03SDaniel P. Berrange 3476278ae03SDaniel P. Berrange # First we'll open the image using cryptsetup and write a 3486278ae03SDaniel P. Berrange # known pattern of data that we'll then verify with QEMU 3496278ae03SDaniel P. Berrange 3506278ae03SDaniel P. Berrange iotests.log("# Open dev") 3516278ae03SDaniel P. Berrange cryptsetup_open(config) 3526278ae03SDaniel P. Berrange 3536278ae03SDaniel P. Berrange try: 3546278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0xa7") 3556278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True) 3566278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x13") 3576278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x13, highOffsetMB, 10, dev=True) 3586278ae03SDaniel P. Berrange finally: 3596278ae03SDaniel P. Berrange iotests.log("# Close dev") 3606278ae03SDaniel P. Berrange cryptsetup_close(config) 3616278ae03SDaniel P. Berrange 3626278ae03SDaniel P. Berrange # Ok, now we're using QEMU to verify the pattern just 3636278ae03SDaniel P. Berrange # written via dm-crypt 3646278ae03SDaniel P. Berrange 3656278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0xa7") 3666278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0xa7, lowOffsetMB, 10, dev=False) 3676278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x13") 3686278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x13, highOffsetMB, 10, dev=False) 3696278ae03SDaniel P. Berrange 3706278ae03SDaniel P. Berrange 3716278ae03SDaniel P. Berrange # Write a new pattern to the image, which we'll later 3726278ae03SDaniel P. Berrange # verify with dm-crypt 3736278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x91") 3746278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x91, lowOffsetMB, 10, dev=False) 3756278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x5e") 3766278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x5e, highOffsetMB, 10, dev=False) 3776278ae03SDaniel P. Berrange 3786278ae03SDaniel P. Berrange 3796278ae03SDaniel P. Berrange # Now we're opening the image with dm-crypt once more 3806278ae03SDaniel P. Berrange # and verifying what QEMU wrote, completing the circle 3816278ae03SDaniel P. Berrange iotests.log("# Open dev") 3826278ae03SDaniel P. Berrange cryptsetup_open(config) 3836278ae03SDaniel P. Berrange 3846278ae03SDaniel P. Berrange try: 3856278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x91") 3866278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True) 3876278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x5e") 3886278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x5e, highOffsetMB, 10, dev=True) 3896278ae03SDaniel P. Berrange finally: 3906278ae03SDaniel P. Berrange iotests.log("# Close dev") 3916278ae03SDaniel P. Berrange cryptsetup_close(config) 3926278ae03SDaniel P. Berrange finally: 3936278ae03SDaniel P. Berrange iotests.log("# Delete image") 3946278ae03SDaniel P. Berrange delete_image(config) 395f03868bdSEduardo Habkost print() 3966278ae03SDaniel P. Berrange 3976278ae03SDaniel P. Berrange 3986278ae03SDaniel P. Berrange# Obviously we only work with the luks image format 3997d814059SJohn Snowiotests.script_initialize(supported_fmts=['luks']) 4006278ae03SDaniel P. Berrange 4016278ae03SDaniel P. Berrange# We need sudo in order to run cryptsetup to create 4026278ae03SDaniel P. Berrange# dm-crypt devices. This is safe to use on any 4036278ae03SDaniel P. Berrange# machine, since all dm-crypt devices are backed 4046278ae03SDaniel P. Berrange# by newly created plain files, and have a dm-crypt 4056278ae03SDaniel P. Berrange# name prefix of 'qiotest' to avoid clashing with 4066278ae03SDaniel P. Berrange# user LUKS volumes 4076278ae03SDaniel P. Berrangeverify_passwordless_sudo() 4086278ae03SDaniel P. Berrange 4096278ae03SDaniel P. Berrange 4106278ae03SDaniel P. Berrange# If we look at all permutations of cipher, key size, 4116278ae03SDaniel P. Berrange# mode, ivgen, hash, there are ~1000 possible configs. 4126278ae03SDaniel P. Berrange# 4136278ae03SDaniel P. Berrange# We certainly don't want/need to test every permutation 4146278ae03SDaniel P. Berrange# to get good validation of interoperability between QEMU 4156278ae03SDaniel P. Berrange# and dm-crypt/cryptsetup. 4166278ae03SDaniel P. Berrange# 4176278ae03SDaniel P. Berrange# The configs below are a representative set that aim to 4186278ae03SDaniel P. Berrange# exercise each axis of configurability. 4196278ae03SDaniel P. Berrange# 4206278ae03SDaniel P. Berrangeconfigs = [ 4216278ae03SDaniel P. Berrange # A common LUKS default 4226278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha1", 4236278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha1"), 4246278ae03SDaniel P. Berrange 4256278ae03SDaniel P. Berrange 4266278ae03SDaniel P. Berrange # LUKS default but diff ciphers 4276278ae03SDaniel P. Berrange LUKSConfig("twofish-256-xts-plain64-sha1", 4286278ae03SDaniel P. Berrange "twofish", 256, "xts", "plain64", None, "sha1"), 4296278ae03SDaniel P. Berrange LUKSConfig("serpent-256-xts-plain64-sha1", 4306278ae03SDaniel P. Berrange "serpent", 256, "xts", "plain64", None, "sha1"), 4316278ae03SDaniel P. Berrange # Should really be xts, but kernel doesn't support xts+cast5 4326278ae03SDaniel P. Berrange # nor does it do essiv+cast5 4336278ae03SDaniel P. Berrange LUKSConfig("cast5-128-cbc-plain64-sha1", 4346278ae03SDaniel P. Berrange "cast5", 128, "cbc", "plain64", None, "sha1"), 4356278ae03SDaniel P. Berrange LUKSConfig("cast6-256-xts-plain64-sha1", 4366278ae03SDaniel P. Berrange "cast6", 256, "xts", "plain64", None, "sha1"), 4376278ae03SDaniel P. Berrange 4386278ae03SDaniel P. Berrange 4396278ae03SDaniel P. Berrange # LUKS default but diff modes / ivgens 4406278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain-sha1", 4416278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain", None, "sha1"), 4426278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain64-sha1", 4436278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain64", None, "sha1"), 4446278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-essiv-sha256-sha1", 4456278ae03SDaniel P. Berrange "aes", 256, "cbc", "essiv", "sha256", "sha1"), 4466278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-essiv-sha256-sha1", 4476278ae03SDaniel P. Berrange "aes", 256, "xts", "essiv", "sha256", "sha1"), 4486278ae03SDaniel P. Berrange 4496278ae03SDaniel P. Berrange 4506278ae03SDaniel P. Berrange # LUKS default but smaller key sizes 4516278ae03SDaniel P. Berrange LUKSConfig("aes-128-xts-plain64-sha256-sha1", 4526278ae03SDaniel P. Berrange "aes", 128, "xts", "plain64", None, "sha1"), 4536278ae03SDaniel P. Berrange LUKSConfig("aes-192-xts-plain64-sha256-sha1", 4546278ae03SDaniel P. Berrange "aes", 192, "xts", "plain64", None, "sha1"), 4556278ae03SDaniel P. Berrange 4566278ae03SDaniel P. Berrange LUKSConfig("twofish-128-xts-plain64-sha1", 4576278ae03SDaniel P. Berrange "twofish", 128, "xts", "plain64", None, "sha1"), 4586278ae03SDaniel P. Berrange LUKSConfig("twofish-192-xts-plain64-sha1", 4596278ae03SDaniel P. Berrange "twofish", 192, "xts", "plain64", None, "sha1"), 4606278ae03SDaniel P. Berrange 4616278ae03SDaniel P. Berrange LUKSConfig("serpent-128-xts-plain64-sha1", 4626278ae03SDaniel P. Berrange "serpent", 128, "xts", "plain64", None, "sha1"), 4636278ae03SDaniel P. Berrange LUKSConfig("serpent-192-xts-plain64-sha1", 4646278ae03SDaniel P. Berrange "serpent", 192, "xts", "plain64", None, "sha1"), 4656278ae03SDaniel P. Berrange 4666278ae03SDaniel P. Berrange LUKSConfig("cast6-128-xts-plain64-sha1", 4676278ae03SDaniel P. Berrange "cast6", 128, "xts", "plain", None, "sha1"), 4686278ae03SDaniel P. Berrange LUKSConfig("cast6-192-xts-plain64-sha1", 4696278ae03SDaniel P. Berrange "cast6", 192, "xts", "plain64", None, "sha1"), 4706278ae03SDaniel P. Berrange 4716278ae03SDaniel P. Berrange 4726278ae03SDaniel P. Berrange # LUKS default but diff hash 473a488e71eSDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha224", 474a488e71eSDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha224"), 4756278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha256", 4766278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha256"), 477a488e71eSDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha384", 478a488e71eSDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha384"), 4796278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha512", 4806278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha512"), 4816278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-ripemd160", 4826278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "ripemd160"), 4836278ae03SDaniel P. Berrange 4846278ae03SDaniel P. Berrange # Password in slot 3 4856278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwslot3", 4866278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 4876278ae03SDaniel P. Berrange passwords={ 4886278ae03SDaniel P. Berrange "3": "slot3", 4896278ae03SDaniel P. Berrange }), 4906278ae03SDaniel P. Berrange 4916278ae03SDaniel P. Berrange # Passwords in every slot 4926278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwallslots", 4936278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 4946278ae03SDaniel P. Berrange passwords={ 4956278ae03SDaniel P. Berrange "0": "slot1", 4966278ae03SDaniel P. Berrange "1": "slot1", 4976278ae03SDaniel P. Berrange "2": "slot2", 4986278ae03SDaniel P. Berrange "3": "slot3", 4996278ae03SDaniel P. Berrange "4": "slot4", 5006278ae03SDaniel P. Berrange "5": "slot5", 5016278ae03SDaniel P. Berrange "6": "slot6", 5026278ae03SDaniel P. Berrange "7": "slot7", 5036278ae03SDaniel P. Berrange }), 5048b7cdba3SDaniel P. Berrange 5058b7cdba3SDaniel P. Berrange # Check handling of default hash alg (sha256) with essiv 5068b7cdba3SDaniel P. Berrange LUKSConfig("aes-256-cbc-essiv-auto-sha1", 5078b7cdba3SDaniel P. Berrange "aes", 256, "cbc", "essiv", None, "sha1"), 5088b7cdba3SDaniel P. Berrange 5098b7cdba3SDaniel P. Berrange # Check that a useless hash provided for 'plain64' iv gen 5108b7cdba3SDaniel P. Berrange # is ignored and no error raised 5118b7cdba3SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain64-sha256-sha1", 5128b7cdba3SDaniel P. Berrange "aes", 256, "cbc", "plain64", "sha256", "sha1"), 5138b7cdba3SDaniel P. Berrange 5146278ae03SDaniel P. Berrange] 5156278ae03SDaniel P. Berrange 5166278ae03SDaniel P. Berrangeblacklist = [ 5176278ae03SDaniel P. Berrange # We don't have a cast-6 cipher impl for QEMU yet 5186278ae03SDaniel P. Berrange "cast6-256-xts-plain64-sha1", 5196278ae03SDaniel P. Berrange "cast6-128-xts-plain64-sha1", 5206278ae03SDaniel P. Berrange "cast6-192-xts-plain64-sha1", 5216278ae03SDaniel P. Berrange 5226278ae03SDaniel P. Berrange # GCrypt doesn't support Twofish with 192 bit key 5236278ae03SDaniel P. Berrange "twofish-192-xts-plain64-sha1", 5246278ae03SDaniel P. Berrange] 5256278ae03SDaniel P. Berrange 5266278ae03SDaniel P. Berrangewhitelist = [] 5276278ae03SDaniel P. Berrangeif "LUKS_CONFIG" in os.environ: 5286278ae03SDaniel P. Berrange whitelist = os.environ["LUKS_CONFIG"].split(",") 5296278ae03SDaniel P. Berrange 5306278ae03SDaniel P. Berrangefor config in configs: 5316278ae03SDaniel P. Berrange if config.name in blacklist: 5326278ae03SDaniel P. Berrange iotests.log("Skipping %s in blacklist" % config.name) 5336278ae03SDaniel P. Berrange continue 5346278ae03SDaniel P. Berrange 5356278ae03SDaniel P. Berrange if len(whitelist) > 0 and config.name not in whitelist: 5366278ae03SDaniel P. Berrange iotests.log("Skipping %s not in whitelist" % config.name) 5376278ae03SDaniel P. Berrange continue 5386278ae03SDaniel P. Berrange 5396278ae03SDaniel P. Berrange test_once(config, qemu_img=False) 5406278ae03SDaniel P. Berrange 5416278ae03SDaniel P. Berrange # XXX we should support setting passwords in a non-0 5426278ae03SDaniel P. Berrange # key slot with 'qemu-img create' in future 5436278ae03SDaniel P. Berrange (pw, slot) = config.first_password() 5446278ae03SDaniel P. Berrange if slot == "0": 5456278ae03SDaniel P. Berrange test_once(config, qemu_img=True) 546