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 2334dd218fdSHanna Reitzdef check_cipher_support(config, output): 2344dd218fdSHanna Reitz """Check the output of qemu-img or qemu-io for mention of the respective 2354dd218fdSHanna Reitz cipher algorithm being unsupported, and if so, skip this test. 2364dd218fdSHanna Reitz (Returns `output` for convenience.)""" 2374dd218fdSHanna Reitz 2384dd218fdSHanna Reitz if 'Unsupported cipher algorithm' in output: 2394dd218fdSHanna Reitz iotests.notrun('Unsupported cipher algorithm ' 2404dd218fdSHanna Reitz f'{config.cipher}-{config.keylen}-{config.mode}; ' 2414dd218fdSHanna Reitz 'consider configuring qemu with a different crypto ' 2424dd218fdSHanna Reitz 'backend') 2434dd218fdSHanna Reitz return output 2444dd218fdSHanna 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]) 26888baae55SJohn Snow try: 26988baae55SJohn Snow iotests.qemu_img(*args) 27088baae55SJohn Snow except subprocess.CalledProcessError as exc: 27188baae55SJohn Snow check_cipher_support(config, exc.output) 27288baae55SJohn Snow raise 2736278ae03SDaniel P. Berrange 2746278ae03SDaniel P. Berrangedef qemu_io_image_args(config, dev=False): 2756278ae03SDaniel P. Berrange """Get the args for access an image or device with qemu-io""" 2766278ae03SDaniel P. Berrange 2776278ae03SDaniel P. Berrange if dev: 2786278ae03SDaniel P. Berrange return [ 2796278ae03SDaniel P. Berrange "--image-opts", 2804e04f3d9SKevin Wolf "driver=host_device,filename=%s" % config.device_path()] 2816278ae03SDaniel P. Berrange else: 2826278ae03SDaniel P. Berrange return [ 2836278ae03SDaniel P. Berrange "--object", 2846278ae03SDaniel P. Berrange ("secret,id=sec0,data=%s,format=base64" % 2856278ae03SDaniel P. Berrange config.first_password_base64()), 2866278ae03SDaniel P. Berrange "--image-opts", 2876278ae03SDaniel P. Berrange ("driver=luks,key-secret=sec0,file.filename=%s" % 2886278ae03SDaniel P. Berrange config.image_path())] 2896278ae03SDaniel P. Berrange 2906278ae03SDaniel P. Berrangedef qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): 2916278ae03SDaniel P. Berrange """Write a pattern of data to a LUKS image or device""" 2926278ae03SDaniel P. Berrange 293ae50b71dSDaniel P. Berrange if dev: 294ae50b71dSDaniel P. Berrange chown(config) 2956278ae03SDaniel P. Berrange args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 2966278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 2976278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 2986dede6a4SJohn Snow output = iotests.qemu_io(*args, check=False).stdout 2996dede6a4SJohn Snow iotests.log(check_cipher_support(config, output), 3004dd218fdSHanna Reitz filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) 3016278ae03SDaniel P. Berrange 3026278ae03SDaniel P. Berrange 3036278ae03SDaniel P. Berrangedef qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): 3046278ae03SDaniel P. Berrange """Read a pattern of data to a LUKS image or device""" 3056278ae03SDaniel P. Berrange 306ae50b71dSDaniel P. Berrange if dev: 307ae50b71dSDaniel P. Berrange chown(config) 3086278ae03SDaniel P. Berrange args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 3096278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 3106278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 3116dede6a4SJohn Snow output = iotests.qemu_io(*args, check=False).stdout 3126dede6a4SJohn Snow iotests.log(check_cipher_support(config, output), 3134dd218fdSHanna Reitz filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) 3146278ae03SDaniel P. Berrange 3156278ae03SDaniel P. Berrange 3166278ae03SDaniel P. Berrangedef test_once(config, qemu_img=False): 3176278ae03SDaniel P. Berrange """Run the test with a desired LUKS configuration. Can either 3186278ae03SDaniel P. Berrange use qemu-img for creating the initial volume, or cryptsetup, 3196278ae03SDaniel P. Berrange in order to test interoperability in both directions""" 3206278ae03SDaniel P. Berrange 3216278ae03SDaniel P. Berrange iotests.log("# ================= %s %s =================" % ( 3226278ae03SDaniel P. Berrange "qemu-img" if qemu_img else "dm-crypt", config)) 3236278ae03SDaniel P. Berrange 3246278ae03SDaniel P. Berrange oneKB = 1024 3256278ae03SDaniel P. Berrange oneMB = oneKB * 1024 3266278ae03SDaniel P. Berrange oneGB = oneMB * 1024 3276278ae03SDaniel P. Berrange oneTB = oneGB * 1024 3286278ae03SDaniel P. Berrange 3296278ae03SDaniel P. Berrange # 4 TB, so that we pass the 32-bit sector number boundary. 3306278ae03SDaniel P. Berrange # Important for testing correctness of some IV generators 3316278ae03SDaniel P. Berrange # The files are sparse, so not actually using this much space 3326278ae03SDaniel P. Berrange image_size = 4 * oneTB 3336278ae03SDaniel P. Berrange if qemu_img: 3346278ae03SDaniel P. Berrange iotests.log("# Create image") 3359a3a9a63SMax Reitz qemu_img_create(config, image_size // oneMB) 3366278ae03SDaniel P. Berrange else: 3376278ae03SDaniel P. Berrange iotests.log("# Create image") 3389a3a9a63SMax Reitz create_image(config, image_size // oneMB) 3396278ae03SDaniel P. Berrange 3406278ae03SDaniel P. Berrange lowOffsetMB = 100 3419a3a9a63SMax Reitz highOffsetMB = 3 * oneTB // oneMB 3426278ae03SDaniel P. Berrange 3436278ae03SDaniel P. Berrange try: 3446278ae03SDaniel P. Berrange if not qemu_img: 3456278ae03SDaniel P. Berrange iotests.log("# Format image") 3466278ae03SDaniel P. Berrange cryptsetup_format(config) 3476278ae03SDaniel P. Berrange 3486278ae03SDaniel P. Berrange for slot in config.active_slots()[1:]: 3496278ae03SDaniel P. Berrange iotests.log("# Add password slot %s" % slot) 3506278ae03SDaniel P. Berrange cryptsetup_add_password(config, slot) 3516278ae03SDaniel P. Berrange 3526278ae03SDaniel P. Berrange # First we'll open the image using cryptsetup and write a 3536278ae03SDaniel P. Berrange # known pattern of data that we'll then verify with QEMU 3546278ae03SDaniel P. Berrange 3556278ae03SDaniel P. Berrange iotests.log("# Open dev") 3566278ae03SDaniel P. Berrange cryptsetup_open(config) 3576278ae03SDaniel P. Berrange 3586278ae03SDaniel P. Berrange try: 3596278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0xa7") 3606278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True) 3616278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x13") 3626278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x13, highOffsetMB, 10, dev=True) 3636278ae03SDaniel P. Berrange finally: 3646278ae03SDaniel P. Berrange iotests.log("# Close dev") 3656278ae03SDaniel P. Berrange cryptsetup_close(config) 3666278ae03SDaniel P. Berrange 3676278ae03SDaniel P. Berrange # Ok, now we're using QEMU to verify the pattern just 3686278ae03SDaniel P. Berrange # written via dm-crypt 3696278ae03SDaniel P. Berrange 3706278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0xa7") 3716278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0xa7, lowOffsetMB, 10, dev=False) 3726278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x13") 3736278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x13, highOffsetMB, 10, dev=False) 3746278ae03SDaniel P. Berrange 3756278ae03SDaniel P. Berrange 3766278ae03SDaniel P. Berrange # Write a new pattern to the image, which we'll later 3776278ae03SDaniel P. Berrange # verify with dm-crypt 3786278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x91") 3796278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x91, lowOffsetMB, 10, dev=False) 3806278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x5e") 3816278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x5e, highOffsetMB, 10, dev=False) 3826278ae03SDaniel P. Berrange 3836278ae03SDaniel P. Berrange 3846278ae03SDaniel P. Berrange # Now we're opening the image with dm-crypt once more 3856278ae03SDaniel P. Berrange # and verifying what QEMU wrote, completing the circle 3866278ae03SDaniel P. Berrange iotests.log("# Open dev") 3876278ae03SDaniel P. Berrange cryptsetup_open(config) 3886278ae03SDaniel P. Berrange 3896278ae03SDaniel P. Berrange try: 3906278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x91") 3916278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True) 3926278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x5e") 3936278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x5e, highOffsetMB, 10, dev=True) 3946278ae03SDaniel P. Berrange finally: 3956278ae03SDaniel P. Berrange iotests.log("# Close dev") 3966278ae03SDaniel P. Berrange cryptsetup_close(config) 3976278ae03SDaniel P. Berrange finally: 3986278ae03SDaniel P. Berrange iotests.log("# Delete image") 3996278ae03SDaniel P. Berrange delete_image(config) 400f03868bdSEduardo Habkost print() 4016278ae03SDaniel P. Berrange 4026278ae03SDaniel P. Berrange 4036278ae03SDaniel P. Berrange# Obviously we only work with the luks image format 4047d814059SJohn Snowiotests.script_initialize(supported_fmts=['luks']) 4056278ae03SDaniel P. Berrange 4066278ae03SDaniel P. Berrange# We need sudo in order to run cryptsetup to create 4076278ae03SDaniel P. Berrange# dm-crypt devices. This is safe to use on any 4086278ae03SDaniel P. Berrange# machine, since all dm-crypt devices are backed 4096278ae03SDaniel P. Berrange# by newly created plain files, and have a dm-crypt 4106278ae03SDaniel P. Berrange# name prefix of 'qiotest' to avoid clashing with 4116278ae03SDaniel P. Berrange# user LUKS volumes 4126278ae03SDaniel P. Berrangeverify_passwordless_sudo() 4136278ae03SDaniel P. Berrange 4146278ae03SDaniel P. Berrange 4156278ae03SDaniel P. Berrange# If we look at all permutations of cipher, key size, 4166278ae03SDaniel P. Berrange# mode, ivgen, hash, there are ~1000 possible configs. 4176278ae03SDaniel P. Berrange# 4186278ae03SDaniel P. Berrange# We certainly don't want/need to test every permutation 4196278ae03SDaniel P. Berrange# to get good validation of interoperability between QEMU 4206278ae03SDaniel P. Berrange# and dm-crypt/cryptsetup. 4216278ae03SDaniel P. Berrange# 4226278ae03SDaniel P. Berrange# The configs below are a representative set that aim to 4236278ae03SDaniel P. Berrange# exercise each axis of configurability. 4246278ae03SDaniel P. Berrange# 4256278ae03SDaniel P. Berrangeconfigs = [ 4266278ae03SDaniel P. Berrange # A common LUKS default 4276278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha1", 4286278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha1"), 4296278ae03SDaniel P. Berrange 4306278ae03SDaniel P. Berrange 4316278ae03SDaniel P. Berrange # LUKS default but diff ciphers 4326278ae03SDaniel P. Berrange LUKSConfig("twofish-256-xts-plain64-sha1", 4336278ae03SDaniel P. Berrange "twofish", 256, "xts", "plain64", None, "sha1"), 4346278ae03SDaniel P. Berrange LUKSConfig("serpent-256-xts-plain64-sha1", 4356278ae03SDaniel P. Berrange "serpent", 256, "xts", "plain64", None, "sha1"), 4366278ae03SDaniel P. Berrange # Should really be xts, but kernel doesn't support xts+cast5 4376278ae03SDaniel P. Berrange # nor does it do essiv+cast5 4386278ae03SDaniel P. Berrange LUKSConfig("cast5-128-cbc-plain64-sha1", 4396278ae03SDaniel P. Berrange "cast5", 128, "cbc", "plain64", None, "sha1"), 4406278ae03SDaniel P. Berrange LUKSConfig("cast6-256-xts-plain64-sha1", 4416278ae03SDaniel P. Berrange "cast6", 256, "xts", "plain64", None, "sha1"), 4426278ae03SDaniel P. Berrange 4436278ae03SDaniel P. Berrange 4446278ae03SDaniel P. Berrange # LUKS default but diff modes / ivgens 4456278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain-sha1", 4466278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain", None, "sha1"), 4476278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain64-sha1", 4486278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain64", None, "sha1"), 4496278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-essiv-sha256-sha1", 4506278ae03SDaniel P. Berrange "aes", 256, "cbc", "essiv", "sha256", "sha1"), 4516278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-essiv-sha256-sha1", 4526278ae03SDaniel P. Berrange "aes", 256, "xts", "essiv", "sha256", "sha1"), 4536278ae03SDaniel P. Berrange 4546278ae03SDaniel P. Berrange 4556278ae03SDaniel P. Berrange # LUKS default but smaller key sizes 4566278ae03SDaniel P. Berrange LUKSConfig("aes-128-xts-plain64-sha256-sha1", 4576278ae03SDaniel P. Berrange "aes", 128, "xts", "plain64", None, "sha1"), 4586278ae03SDaniel P. Berrange LUKSConfig("aes-192-xts-plain64-sha256-sha1", 4596278ae03SDaniel P. Berrange "aes", 192, "xts", "plain64", None, "sha1"), 4606278ae03SDaniel P. Berrange 4616278ae03SDaniel P. Berrange LUKSConfig("twofish-128-xts-plain64-sha1", 4626278ae03SDaniel P. Berrange "twofish", 128, "xts", "plain64", None, "sha1"), 4636278ae03SDaniel P. Berrange LUKSConfig("twofish-192-xts-plain64-sha1", 4646278ae03SDaniel P. Berrange "twofish", 192, "xts", "plain64", None, "sha1"), 4656278ae03SDaniel P. Berrange 4666278ae03SDaniel P. Berrange LUKSConfig("serpent-128-xts-plain64-sha1", 4676278ae03SDaniel P. Berrange "serpent", 128, "xts", "plain64", None, "sha1"), 4686278ae03SDaniel P. Berrange LUKSConfig("serpent-192-xts-plain64-sha1", 4696278ae03SDaniel P. Berrange "serpent", 192, "xts", "plain64", None, "sha1"), 4706278ae03SDaniel P. Berrange 4716278ae03SDaniel P. Berrange LUKSConfig("cast6-128-xts-plain64-sha1", 4726278ae03SDaniel P. Berrange "cast6", 128, "xts", "plain", None, "sha1"), 4736278ae03SDaniel P. Berrange LUKSConfig("cast6-192-xts-plain64-sha1", 4746278ae03SDaniel P. Berrange "cast6", 192, "xts", "plain64", None, "sha1"), 4756278ae03SDaniel P. Berrange 4766278ae03SDaniel P. Berrange 4776278ae03SDaniel P. Berrange # LUKS default but diff hash 478a488e71eSDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha224", 479a488e71eSDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha224"), 4806278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha256", 4816278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha256"), 482a488e71eSDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha384", 483a488e71eSDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha384"), 4846278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha512", 4856278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha512"), 4866278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-ripemd160", 4876278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "ripemd160"), 4886278ae03SDaniel P. Berrange 4896278ae03SDaniel P. Berrange # Password in slot 3 4906278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwslot3", 4916278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 4926278ae03SDaniel P. Berrange passwords={ 4936278ae03SDaniel P. Berrange "3": "slot3", 4946278ae03SDaniel P. Berrange }), 4956278ae03SDaniel P. Berrange 4966278ae03SDaniel P. Berrange # Passwords in every slot 4976278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwallslots", 4986278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 4996278ae03SDaniel P. Berrange passwords={ 5006278ae03SDaniel P. Berrange "0": "slot1", 5016278ae03SDaniel P. Berrange "1": "slot1", 5026278ae03SDaniel P. Berrange "2": "slot2", 5036278ae03SDaniel P. Berrange "3": "slot3", 5046278ae03SDaniel P. Berrange "4": "slot4", 5056278ae03SDaniel P. Berrange "5": "slot5", 5066278ae03SDaniel P. Berrange "6": "slot6", 5076278ae03SDaniel P. Berrange "7": "slot7", 5086278ae03SDaniel P. Berrange }), 5098b7cdba3SDaniel P. Berrange 5108b7cdba3SDaniel P. Berrange # Check handling of default hash alg (sha256) with essiv 5118b7cdba3SDaniel P. Berrange LUKSConfig("aes-256-cbc-essiv-auto-sha1", 5128b7cdba3SDaniel P. Berrange "aes", 256, "cbc", "essiv", None, "sha1"), 5138b7cdba3SDaniel P. Berrange 5148b7cdba3SDaniel P. Berrange # Check that a useless hash provided for 'plain64' iv gen 5158b7cdba3SDaniel P. Berrange # is ignored and no error raised 5168b7cdba3SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain64-sha256-sha1", 5178b7cdba3SDaniel P. Berrange "aes", 256, "cbc", "plain64", "sha256", "sha1"), 5188b7cdba3SDaniel P. Berrange 5196278ae03SDaniel P. Berrange] 5206278ae03SDaniel P. Berrange 521*5689d4bdSThomas Huthunsupported_configs = [ 5226278ae03SDaniel P. Berrange # We don't have a cast-6 cipher impl for QEMU yet 5236278ae03SDaniel P. Berrange "cast6-256-xts-plain64-sha1", 5246278ae03SDaniel P. Berrange "cast6-128-xts-plain64-sha1", 5256278ae03SDaniel P. Berrange "cast6-192-xts-plain64-sha1", 5266278ae03SDaniel P. Berrange 5276278ae03SDaniel P. Berrange # GCrypt doesn't support Twofish with 192 bit key 5286278ae03SDaniel P. Berrange "twofish-192-xts-plain64-sha1", 5296278ae03SDaniel P. Berrange] 5306278ae03SDaniel P. Berrange 531*5689d4bdSThomas Huth# Optionally test only the configurations in the LUKS_CONFIG 532*5689d4bdSThomas Huth# environment variable 533*5689d4bdSThomas Huthtested_configs = None 5346278ae03SDaniel P. Berrangeif "LUKS_CONFIG" in os.environ: 535*5689d4bdSThomas Huth tested_configs = os.environ["LUKS_CONFIG"].split(",") 5366278ae03SDaniel P. Berrange 5376278ae03SDaniel P. Berrangefor config in configs: 538*5689d4bdSThomas Huth if config.name in unsupported_configs: 539*5689d4bdSThomas Huth iotests.log("Skipping %s (config not supported)" % config.name) 5406278ae03SDaniel P. Berrange continue 5416278ae03SDaniel P. Berrange 542*5689d4bdSThomas Huth if tested_configs is not None and config.name not in tested_configs: 543*5689d4bdSThomas Huth iotests.log("Skipping %s (by user request)" % config.name) 5446278ae03SDaniel P. Berrange continue 5456278ae03SDaniel P. Berrange 5466278ae03SDaniel P. Berrange test_once(config, qemu_img=False) 5476278ae03SDaniel P. Berrange 5486278ae03SDaniel P. Berrange # XXX we should support setting passwords in a non-0 5496278ae03SDaniel P. Berrange # key slot with 'qemu-img create' in future 5506278ae03SDaniel P. Berrange (pw, slot) = config.first_password() 5516278ae03SDaniel P. Berrange if slot == "0": 5526278ae03SDaniel P. Berrange test_once(config, qemu_img=True) 553