1*6278ae03SDaniel P. Berrange#!/usr/bin/python 2*6278ae03SDaniel P. Berrange# 3*6278ae03SDaniel P. Berrange# Copyright (C) 2016 Red Hat, Inc. 4*6278ae03SDaniel P. Berrange# 5*6278ae03SDaniel P. Berrange# This program is free software; you can redistribute it and/or modify 6*6278ae03SDaniel P. Berrange# it under the terms of the GNU General Public License as published by 7*6278ae03SDaniel P. Berrange# the Free Software Foundation; either version 2 of the License, or 8*6278ae03SDaniel P. Berrange# (at your option) any later version. 9*6278ae03SDaniel P. Berrange# 10*6278ae03SDaniel P. Berrange# This program is distributed in the hope that it will be useful, 11*6278ae03SDaniel P. Berrange# but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6278ae03SDaniel P. Berrange# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6278ae03SDaniel P. Berrange# GNU General Public License for more details. 14*6278ae03SDaniel P. Berrange# 15*6278ae03SDaniel P. Berrange# You should have received a copy of the GNU General Public License 16*6278ae03SDaniel P. Berrange# along with this program. If not, see <http://www.gnu.org/licenses/>. 17*6278ae03SDaniel P. Berrange# 18*6278ae03SDaniel P. Berrange# Creator/Owner: Daniel P. Berrange <berrange@redhat.com> 19*6278ae03SDaniel P. Berrange# 20*6278ae03SDaniel P. Berrange# Exercise the QEMU 'luks' block driver to validate interoperability 21*6278ae03SDaniel P. Berrange# with the Linux dm-crypt + cryptsetup implementation 22*6278ae03SDaniel P. Berrange 23*6278ae03SDaniel P. Berrangeimport subprocess 24*6278ae03SDaniel P. Berrangeimport os 25*6278ae03SDaniel P. Berrangeimport os.path 26*6278ae03SDaniel P. Berrange 27*6278ae03SDaniel P. Berrangeimport base64 28*6278ae03SDaniel P. Berrange 29*6278ae03SDaniel P. Berrangeimport iotests 30*6278ae03SDaniel P. Berrange 31*6278ae03SDaniel P. Berrange 32*6278ae03SDaniel P. Berrangeclass LUKSConfig(object): 33*6278ae03SDaniel P. Berrange """Represent configuration parameters for a single LUKS 34*6278ae03SDaniel P. Berrange setup to be tested""" 35*6278ae03SDaniel P. Berrange 36*6278ae03SDaniel P. Berrange def __init__(self, name, cipher, keylen, mode, ivgen, 37*6278ae03SDaniel P. Berrange ivgen_hash, hash, password=None, passwords=None): 38*6278ae03SDaniel P. Berrange 39*6278ae03SDaniel P. Berrange self.name = name 40*6278ae03SDaniel P. Berrange self.cipher = cipher 41*6278ae03SDaniel P. Berrange self.keylen = keylen 42*6278ae03SDaniel P. Berrange self.mode = mode 43*6278ae03SDaniel P. Berrange self.ivgen = ivgen 44*6278ae03SDaniel P. Berrange self.ivgen_hash = ivgen_hash 45*6278ae03SDaniel P. Berrange self.hash = hash 46*6278ae03SDaniel P. Berrange 47*6278ae03SDaniel P. Berrange if passwords is not None: 48*6278ae03SDaniel P. Berrange self.passwords = passwords 49*6278ae03SDaniel P. Berrange else: 50*6278ae03SDaniel P. Berrange self.passwords = {} 51*6278ae03SDaniel P. Berrange 52*6278ae03SDaniel P. Berrange if password is None: 53*6278ae03SDaniel P. Berrange self.passwords["0"] = "123456" 54*6278ae03SDaniel P. Berrange else: 55*6278ae03SDaniel P. Berrange self.passwords["0"] = password 56*6278ae03SDaniel P. Berrange 57*6278ae03SDaniel P. Berrange def __repr__(self): 58*6278ae03SDaniel P. Berrange return self.name 59*6278ae03SDaniel P. Berrange 60*6278ae03SDaniel P. Berrange def image_name(self): 61*6278ae03SDaniel P. Berrange return "luks-%s.img" % self.name 62*6278ae03SDaniel P. Berrange 63*6278ae03SDaniel P. Berrange def image_path(self): 64*6278ae03SDaniel P. Berrange return os.path.join(iotests.test_dir, self.image_name()) 65*6278ae03SDaniel P. Berrange 66*6278ae03SDaniel P. Berrange def device_name(self): 67*6278ae03SDaniel P. Berrange return "qiotest-145-%s" % self.name 68*6278ae03SDaniel P. Berrange 69*6278ae03SDaniel P. Berrange def device_path(self): 70*6278ae03SDaniel P. Berrange return "/dev/mapper/" + self.device_name() 71*6278ae03SDaniel P. Berrange 72*6278ae03SDaniel P. Berrange def first_password(self): 73*6278ae03SDaniel P. Berrange for i in range(8): 74*6278ae03SDaniel P. Berrange slot = str(i) 75*6278ae03SDaniel P. Berrange if slot in self.passwords: 76*6278ae03SDaniel P. Berrange return (self.passwords[slot], slot) 77*6278ae03SDaniel P. Berrange raise Exception("No password found") 78*6278ae03SDaniel P. Berrange 79*6278ae03SDaniel P. Berrange def first_password_base64(self): 80*6278ae03SDaniel P. Berrange (pw, slot) = self.first_password() 81*6278ae03SDaniel P. Berrange return base64.b64encode(pw) 82*6278ae03SDaniel P. Berrange 83*6278ae03SDaniel P. Berrange def active_slots(self): 84*6278ae03SDaniel P. Berrange slots = [] 85*6278ae03SDaniel P. Berrange for i in range(8): 86*6278ae03SDaniel P. Berrange slot = str(i) 87*6278ae03SDaniel P. Berrange if slot in self.passwords: 88*6278ae03SDaniel P. Berrange slots.append(slot) 89*6278ae03SDaniel P. Berrange return slots 90*6278ae03SDaniel P. Berrange 91*6278ae03SDaniel P. Berrangedef verify_passwordless_sudo(): 92*6278ae03SDaniel P. Berrange """Check whether sudo is configured to allow 93*6278ae03SDaniel P. Berrange password-less access to commands""" 94*6278ae03SDaniel P. Berrange 95*6278ae03SDaniel P. Berrange args = ["sudo", "-n", "/bin/true"] 96*6278ae03SDaniel P. Berrange 97*6278ae03SDaniel P. Berrange proc = subprocess.Popen(args, 98*6278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 99*6278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 100*6278ae03SDaniel P. Berrange stderr=subprocess.STDOUT) 101*6278ae03SDaniel P. Berrange 102*6278ae03SDaniel P. Berrange msg = proc.communicate()[0] 103*6278ae03SDaniel P. Berrange 104*6278ae03SDaniel P. Berrange if proc.returncode != 0: 105*6278ae03SDaniel P. Berrange iotests.notrun('requires password-less sudo access: %s' % msg) 106*6278ae03SDaniel P. Berrange 107*6278ae03SDaniel P. Berrange 108*6278ae03SDaniel P. Berrangedef cryptsetup(args, password=None): 109*6278ae03SDaniel P. Berrange """Run the cryptsetup command in batch mode""" 110*6278ae03SDaniel P. Berrange 111*6278ae03SDaniel P. Berrange fullargs = ["sudo", "cryptsetup", "-q", "-v"] 112*6278ae03SDaniel P. Berrange fullargs.extend(args) 113*6278ae03SDaniel P. Berrange 114*6278ae03SDaniel P. Berrange iotests.log(" ".join(fullargs), filters=[iotests.filter_test_dir]) 115*6278ae03SDaniel P. Berrange proc = subprocess.Popen(fullargs, 116*6278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 117*6278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 118*6278ae03SDaniel P. Berrange stderr=subprocess.STDOUT) 119*6278ae03SDaniel P. Berrange 120*6278ae03SDaniel P. Berrange msg = proc.communicate(password)[0] 121*6278ae03SDaniel P. Berrange 122*6278ae03SDaniel P. Berrange if proc.returncode != 0: 123*6278ae03SDaniel P. Berrange raise Exception(msg) 124*6278ae03SDaniel P. Berrange 125*6278ae03SDaniel P. Berrange 126*6278ae03SDaniel P. Berrangedef cryptsetup_add_password(config, slot): 127*6278ae03SDaniel P. Berrange """Add another password to a LUKS key slot""" 128*6278ae03SDaniel P. Berrange 129*6278ae03SDaniel P. Berrange (password, mainslot) = config.first_password() 130*6278ae03SDaniel P. Berrange 131*6278ae03SDaniel P. Berrange pwfile = os.path.join(iotests.test_dir, "passwd.txt") 132*6278ae03SDaniel P. Berrange with open(pwfile, "w") as fh: 133*6278ae03SDaniel P. Berrange fh.write(config.passwords[slot]) 134*6278ae03SDaniel P. Berrange 135*6278ae03SDaniel P. Berrange try: 136*6278ae03SDaniel P. Berrange args = ["luksAddKey", config.image_path(), 137*6278ae03SDaniel P. Berrange "--key-slot", slot, 138*6278ae03SDaniel P. Berrange "--key-file", "-", 139*6278ae03SDaniel P. Berrange pwfile] 140*6278ae03SDaniel P. Berrange 141*6278ae03SDaniel P. Berrange cryptsetup(args, password) 142*6278ae03SDaniel P. Berrange finally: 143*6278ae03SDaniel P. Berrange os.unlink(pwfile) 144*6278ae03SDaniel P. Berrange 145*6278ae03SDaniel P. Berrange 146*6278ae03SDaniel P. Berrangedef cryptsetup_format(config): 147*6278ae03SDaniel P. Berrange """Format a new LUKS volume with cryptsetup, adding the 148*6278ae03SDaniel P. Berrange first key slot only""" 149*6278ae03SDaniel P. Berrange 150*6278ae03SDaniel P. Berrange (password, slot) = config.first_password() 151*6278ae03SDaniel P. Berrange 152*6278ae03SDaniel P. Berrange args = ["luksFormat"] 153*6278ae03SDaniel P. Berrange cipher = config.cipher + "-" + config.mode + "-" + config.ivgen 154*6278ae03SDaniel P. Berrange if config.ivgen_hash is not None: 155*6278ae03SDaniel P. Berrange cipher = cipher + ":" + config.ivgen_hash 156*6278ae03SDaniel P. Berrange args.extend(["--cipher", cipher]) 157*6278ae03SDaniel P. Berrange if config.mode == "xts": 158*6278ae03SDaniel P. Berrange args.extend(["--key-size", str(config.keylen * 2)]) 159*6278ae03SDaniel P. Berrange else: 160*6278ae03SDaniel P. Berrange args.extend(["--key-size", str(config.keylen)]) 161*6278ae03SDaniel P. Berrange if config.hash is not None: 162*6278ae03SDaniel P. Berrange args.extend(["--hash", config.hash]) 163*6278ae03SDaniel P. Berrange args.extend(["--key-slot", slot]) 164*6278ae03SDaniel P. Berrange args.extend(["--key-file", "-"]) 165*6278ae03SDaniel P. Berrange args.append(config.image_path()) 166*6278ae03SDaniel P. Berrange 167*6278ae03SDaniel P. Berrange cryptsetup(args, password) 168*6278ae03SDaniel P. Berrange 169*6278ae03SDaniel P. Berrange 170*6278ae03SDaniel P. Berrangedef chown(config): 171*6278ae03SDaniel P. Berrange """Set the ownership of a open LUKS device to this user""" 172*6278ae03SDaniel P. Berrange 173*6278ae03SDaniel P. Berrange path = config.device_path() 174*6278ae03SDaniel P. Berrange 175*6278ae03SDaniel P. Berrange args = ["sudo", "chown", "%d:%d" % (os.getuid(), os.getgid()), path] 176*6278ae03SDaniel P. Berrange iotests.log(" ".join(args), filters=[iotests.filter_chown]) 177*6278ae03SDaniel P. Berrange proc = subprocess.Popen(args, 178*6278ae03SDaniel P. Berrange stdin=subprocess.PIPE, 179*6278ae03SDaniel P. Berrange stdout=subprocess.PIPE, 180*6278ae03SDaniel P. Berrange stderr=subprocess.STDOUT) 181*6278ae03SDaniel P. Berrange 182*6278ae03SDaniel P. Berrange msg = proc.communicate()[0] 183*6278ae03SDaniel P. Berrange 184*6278ae03SDaniel P. Berrange if proc.returncode != 0: 185*6278ae03SDaniel P. Berrange raise Exception("Cannot change owner on %s" % path) 186*6278ae03SDaniel P. Berrange 187*6278ae03SDaniel P. Berrange 188*6278ae03SDaniel P. Berrangedef cryptsetup_open(config): 189*6278ae03SDaniel P. Berrange """Open an image as a LUKS device""" 190*6278ae03SDaniel P. Berrange 191*6278ae03SDaniel P. Berrange (password, slot) = config.first_password() 192*6278ae03SDaniel P. Berrange 193*6278ae03SDaniel P. Berrange args = ["luksOpen", config.image_path(), config.device_name()] 194*6278ae03SDaniel P. Berrange 195*6278ae03SDaniel P. Berrange cryptsetup(args, password) 196*6278ae03SDaniel P. Berrange 197*6278ae03SDaniel P. Berrange 198*6278ae03SDaniel P. Berrangedef cryptsetup_close(config): 199*6278ae03SDaniel P. Berrange """Close an active LUKS device """ 200*6278ae03SDaniel P. Berrange 201*6278ae03SDaniel P. Berrange args = ["luksClose", config.device_name()] 202*6278ae03SDaniel P. Berrange cryptsetup(args) 203*6278ae03SDaniel P. Berrange 204*6278ae03SDaniel P. Berrange 205*6278ae03SDaniel P. Berrangedef delete_image(config): 206*6278ae03SDaniel P. Berrange """Delete a disk image""" 207*6278ae03SDaniel P. Berrange 208*6278ae03SDaniel P. Berrange try: 209*6278ae03SDaniel P. Berrange os.unlink(config.image_path()) 210*6278ae03SDaniel P. Berrange iotests.log("unlink %s" % config.image_path(), 211*6278ae03SDaniel P. Berrange filters=[iotests.filter_test_dir]) 212*6278ae03SDaniel P. Berrange except Exception as e: 213*6278ae03SDaniel P. Berrange pass 214*6278ae03SDaniel P. Berrange 215*6278ae03SDaniel P. Berrange 216*6278ae03SDaniel P. Berrangedef create_image(config, size_mb): 217*6278ae03SDaniel P. Berrange """Create a bare disk image with requested size""" 218*6278ae03SDaniel P. Berrange 219*6278ae03SDaniel P. Berrange delete_image(config) 220*6278ae03SDaniel P. Berrange iotests.log("truncate %s --size %dMB" % (config.image_path(), size_mb), 221*6278ae03SDaniel P. Berrange filters=[iotests.filter_test_dir]) 222*6278ae03SDaniel P. Berrange with open(config.image_path(), "w") as fn: 223*6278ae03SDaniel P. Berrange fn.truncate(size_mb * 1024 * 1024) 224*6278ae03SDaniel P. Berrange 225*6278ae03SDaniel P. Berrange 226*6278ae03SDaniel P. Berrangedef qemu_img_create(config, size_mb): 227*6278ae03SDaniel P. Berrange """Create and format a disk image with LUKS using qemu-img""" 228*6278ae03SDaniel P. Berrange 229*6278ae03SDaniel P. Berrange opts = [ 230*6278ae03SDaniel P. Berrange "key-secret=sec0", 231*6278ae03SDaniel P. Berrange "cipher-alg=%s-%d" % (config.cipher, config.keylen), 232*6278ae03SDaniel P. Berrange "cipher-mode=%s" % config.mode, 233*6278ae03SDaniel P. Berrange "ivgen-alg=%s" % config.ivgen, 234*6278ae03SDaniel P. Berrange "hash-alg=%s" % config.hash, 235*6278ae03SDaniel P. Berrange ] 236*6278ae03SDaniel P. Berrange if config.ivgen_hash is not None: 237*6278ae03SDaniel P. Berrange opts.append("ivgen-hash-alg=%s" % config.ivgen_hash) 238*6278ae03SDaniel P. Berrange 239*6278ae03SDaniel P. Berrange args = ["create", "-f", "luks", 240*6278ae03SDaniel P. Berrange "--object", 241*6278ae03SDaniel P. Berrange ("secret,id=sec0,data=%s,format=base64" % 242*6278ae03SDaniel P. Berrange config.first_password_base64()), 243*6278ae03SDaniel P. Berrange "-o", ",".join(opts), 244*6278ae03SDaniel P. Berrange config.image_path(), 245*6278ae03SDaniel P. Berrange "%dM" % size_mb] 246*6278ae03SDaniel P. Berrange 247*6278ae03SDaniel P. Berrange iotests.log("qemu-img " + " ".join(args), filters=[iotests.filter_test_dir]) 248*6278ae03SDaniel P. Berrange iotests.log(iotests.qemu_img_pipe(*args), filters=[iotests.filter_test_dir]) 249*6278ae03SDaniel P. Berrange 250*6278ae03SDaniel P. Berrangedef qemu_io_image_args(config, dev=False): 251*6278ae03SDaniel P. Berrange """Get the args for access an image or device with qemu-io""" 252*6278ae03SDaniel P. Berrange 253*6278ae03SDaniel P. Berrange if dev: 254*6278ae03SDaniel P. Berrange return [ 255*6278ae03SDaniel P. Berrange "--image-opts", 256*6278ae03SDaniel P. Berrange "driver=file,filename=%s" % config.device_path()] 257*6278ae03SDaniel P. Berrange else: 258*6278ae03SDaniel P. Berrange return [ 259*6278ae03SDaniel P. Berrange "--object", 260*6278ae03SDaniel P. Berrange ("secret,id=sec0,data=%s,format=base64" % 261*6278ae03SDaniel P. Berrange config.first_password_base64()), 262*6278ae03SDaniel P. Berrange "--image-opts", 263*6278ae03SDaniel P. Berrange ("driver=luks,key-secret=sec0,file.filename=%s" % 264*6278ae03SDaniel P. Berrange config.image_path())] 265*6278ae03SDaniel P. Berrange 266*6278ae03SDaniel P. Berrangedef qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): 267*6278ae03SDaniel P. Berrange """Write a pattern of data to a LUKS image or device""" 268*6278ae03SDaniel P. Berrange 269*6278ae03SDaniel P. Berrange args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 270*6278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 271*6278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 272*6278ae03SDaniel P. Berrange iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir, 273*6278ae03SDaniel P. Berrange iotests.filter_qemu_io]) 274*6278ae03SDaniel P. Berrange 275*6278ae03SDaniel P. Berrange 276*6278ae03SDaniel P. Berrangedef qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): 277*6278ae03SDaniel P. Berrange """Read a pattern of data to a LUKS image or device""" 278*6278ae03SDaniel P. Berrange 279*6278ae03SDaniel P. Berrange args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] 280*6278ae03SDaniel P. Berrange args.extend(qemu_io_image_args(config, dev)) 281*6278ae03SDaniel P. Berrange iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) 282*6278ae03SDaniel P. Berrange iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir, 283*6278ae03SDaniel P. Berrange iotests.filter_qemu_io]) 284*6278ae03SDaniel P. Berrange 285*6278ae03SDaniel P. Berrange 286*6278ae03SDaniel P. Berrangedef test_once(config, qemu_img=False): 287*6278ae03SDaniel P. Berrange """Run the test with a desired LUKS configuration. Can either 288*6278ae03SDaniel P. Berrange use qemu-img for creating the initial volume, or cryptsetup, 289*6278ae03SDaniel P. Berrange in order to test interoperability in both directions""" 290*6278ae03SDaniel P. Berrange 291*6278ae03SDaniel P. Berrange iotests.log("# ================= %s %s =================" % ( 292*6278ae03SDaniel P. Berrange "qemu-img" if qemu_img else "dm-crypt", config)) 293*6278ae03SDaniel P. Berrange 294*6278ae03SDaniel P. Berrange oneKB = 1024 295*6278ae03SDaniel P. Berrange oneMB = oneKB * 1024 296*6278ae03SDaniel P. Berrange oneGB = oneMB * 1024 297*6278ae03SDaniel P. Berrange oneTB = oneGB * 1024 298*6278ae03SDaniel P. Berrange 299*6278ae03SDaniel P. Berrange # 4 TB, so that we pass the 32-bit sector number boundary. 300*6278ae03SDaniel P. Berrange # Important for testing correctness of some IV generators 301*6278ae03SDaniel P. Berrange # The files are sparse, so not actually using this much space 302*6278ae03SDaniel P. Berrange image_size = 4 * oneTB 303*6278ae03SDaniel P. Berrange if qemu_img: 304*6278ae03SDaniel P. Berrange iotests.log("# Create image") 305*6278ae03SDaniel P. Berrange qemu_img_create(config, image_size / oneMB) 306*6278ae03SDaniel P. Berrange else: 307*6278ae03SDaniel P. Berrange iotests.log("# Create image") 308*6278ae03SDaniel P. Berrange create_image(config, image_size / oneMB) 309*6278ae03SDaniel P. Berrange 310*6278ae03SDaniel P. Berrange lowOffsetMB = 100 311*6278ae03SDaniel P. Berrange highOffsetMB = 3 * oneTB / oneMB 312*6278ae03SDaniel P. Berrange 313*6278ae03SDaniel P. Berrange try: 314*6278ae03SDaniel P. Berrange if not qemu_img: 315*6278ae03SDaniel P. Berrange iotests.log("# Format image") 316*6278ae03SDaniel P. Berrange cryptsetup_format(config) 317*6278ae03SDaniel P. Berrange 318*6278ae03SDaniel P. Berrange for slot in config.active_slots()[1:]: 319*6278ae03SDaniel P. Berrange iotests.log("# Add password slot %s" % slot) 320*6278ae03SDaniel P. Berrange cryptsetup_add_password(config, slot) 321*6278ae03SDaniel P. Berrange 322*6278ae03SDaniel P. Berrange # First we'll open the image using cryptsetup and write a 323*6278ae03SDaniel P. Berrange # known pattern of data that we'll then verify with QEMU 324*6278ae03SDaniel P. Berrange 325*6278ae03SDaniel P. Berrange iotests.log("# Open dev") 326*6278ae03SDaniel P. Berrange cryptsetup_open(config) 327*6278ae03SDaniel P. Berrange 328*6278ae03SDaniel P. Berrange try: 329*6278ae03SDaniel P. Berrange iotests.log("# Set dev owner") 330*6278ae03SDaniel P. Berrange chown(config) 331*6278ae03SDaniel P. Berrange 332*6278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0xa7") 333*6278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True) 334*6278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x13") 335*6278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x13, highOffsetMB, 10, dev=True) 336*6278ae03SDaniel P. Berrange finally: 337*6278ae03SDaniel P. Berrange iotests.log("# Close dev") 338*6278ae03SDaniel P. Berrange cryptsetup_close(config) 339*6278ae03SDaniel P. Berrange 340*6278ae03SDaniel P. Berrange # Ok, now we're using QEMU to verify the pattern just 341*6278ae03SDaniel P. Berrange # written via dm-crypt 342*6278ae03SDaniel P. Berrange 343*6278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0xa7") 344*6278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0xa7, lowOffsetMB, 10, dev=False) 345*6278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x13") 346*6278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x13, highOffsetMB, 10, dev=False) 347*6278ae03SDaniel P. Berrange 348*6278ae03SDaniel P. Berrange 349*6278ae03SDaniel P. Berrange # Write a new pattern to the image, which we'll later 350*6278ae03SDaniel P. Berrange # verify with dm-crypt 351*6278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x91") 352*6278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x91, lowOffsetMB, 10, dev=False) 353*6278ae03SDaniel P. Berrange iotests.log("# Write test pattern 0x5e") 354*6278ae03SDaniel P. Berrange qemu_io_write_pattern(config, 0x5e, highOffsetMB, 10, dev=False) 355*6278ae03SDaniel P. Berrange 356*6278ae03SDaniel P. Berrange 357*6278ae03SDaniel P. Berrange # Now we're opening the image with dm-crypt once more 358*6278ae03SDaniel P. Berrange # and verifying what QEMU wrote, completing the circle 359*6278ae03SDaniel P. Berrange iotests.log("# Open dev") 360*6278ae03SDaniel P. Berrange cryptsetup_open(config) 361*6278ae03SDaniel P. Berrange 362*6278ae03SDaniel P. Berrange try: 363*6278ae03SDaniel P. Berrange iotests.log("# Set dev owner") 364*6278ae03SDaniel P. Berrange chown(config) 365*6278ae03SDaniel P. Berrange 366*6278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x91") 367*6278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True) 368*6278ae03SDaniel P. Berrange iotests.log("# Read test pattern 0x5e") 369*6278ae03SDaniel P. Berrange qemu_io_read_pattern(config, 0x5e, highOffsetMB, 10, dev=True) 370*6278ae03SDaniel P. Berrange finally: 371*6278ae03SDaniel P. Berrange iotests.log("# Close dev") 372*6278ae03SDaniel P. Berrange cryptsetup_close(config) 373*6278ae03SDaniel P. Berrange finally: 374*6278ae03SDaniel P. Berrange iotests.log("# Delete image") 375*6278ae03SDaniel P. Berrange delete_image(config) 376*6278ae03SDaniel P. Berrange print 377*6278ae03SDaniel P. Berrange 378*6278ae03SDaniel P. Berrange 379*6278ae03SDaniel P. Berrange# Obviously we only work with the luks image format 380*6278ae03SDaniel P. Berrangeiotests.verify_image_format(supported_fmts=['luks']) 381*6278ae03SDaniel P. Berrangeiotests.verify_platform() 382*6278ae03SDaniel P. Berrange 383*6278ae03SDaniel P. Berrange# We need sudo in order to run cryptsetup to create 384*6278ae03SDaniel P. Berrange# dm-crypt devices. This is safe to use on any 385*6278ae03SDaniel P. Berrange# machine, since all dm-crypt devices are backed 386*6278ae03SDaniel P. Berrange# by newly created plain files, and have a dm-crypt 387*6278ae03SDaniel P. Berrange# name prefix of 'qiotest' to avoid clashing with 388*6278ae03SDaniel P. Berrange# user LUKS volumes 389*6278ae03SDaniel P. Berrangeverify_passwordless_sudo() 390*6278ae03SDaniel P. Berrange 391*6278ae03SDaniel P. Berrange 392*6278ae03SDaniel P. Berrange# If we look at all permutations of cipher, key size, 393*6278ae03SDaniel P. Berrange# mode, ivgen, hash, there are ~1000 possible configs. 394*6278ae03SDaniel P. Berrange# 395*6278ae03SDaniel P. Berrange# We certainly don't want/need to test every permutation 396*6278ae03SDaniel P. Berrange# to get good validation of interoperability between QEMU 397*6278ae03SDaniel P. Berrange# and dm-crypt/cryptsetup. 398*6278ae03SDaniel P. Berrange# 399*6278ae03SDaniel P. Berrange# The configs below are a representative set that aim to 400*6278ae03SDaniel P. Berrange# exercise each axis of configurability. 401*6278ae03SDaniel P. Berrange# 402*6278ae03SDaniel P. Berrangeconfigs = [ 403*6278ae03SDaniel P. Berrange # A common LUKS default 404*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha1", 405*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha1"), 406*6278ae03SDaniel P. Berrange 407*6278ae03SDaniel P. Berrange 408*6278ae03SDaniel P. Berrange # LUKS default but diff ciphers 409*6278ae03SDaniel P. Berrange LUKSConfig("twofish-256-xts-plain64-sha1", 410*6278ae03SDaniel P. Berrange "twofish", 256, "xts", "plain64", None, "sha1"), 411*6278ae03SDaniel P. Berrange LUKSConfig("serpent-256-xts-plain64-sha1", 412*6278ae03SDaniel P. Berrange "serpent", 256, "xts", "plain64", None, "sha1"), 413*6278ae03SDaniel P. Berrange # Should really be xts, but kernel doesn't support xts+cast5 414*6278ae03SDaniel P. Berrange # nor does it do essiv+cast5 415*6278ae03SDaniel P. Berrange LUKSConfig("cast5-128-cbc-plain64-sha1", 416*6278ae03SDaniel P. Berrange "cast5", 128, "cbc", "plain64", None, "sha1"), 417*6278ae03SDaniel P. Berrange LUKSConfig("cast6-256-xts-plain64-sha1", 418*6278ae03SDaniel P. Berrange "cast6", 256, "xts", "plain64", None, "sha1"), 419*6278ae03SDaniel P. Berrange 420*6278ae03SDaniel P. Berrange 421*6278ae03SDaniel P. Berrange # LUKS default but diff modes / ivgens 422*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain-sha1", 423*6278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain", None, "sha1"), 424*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-plain64-sha1", 425*6278ae03SDaniel P. Berrange "aes", 256, "cbc", "plain64", None, "sha1"), 426*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-cbc-essiv-sha256-sha1", 427*6278ae03SDaniel P. Berrange "aes", 256, "cbc", "essiv", "sha256", "sha1"), 428*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-essiv-sha256-sha1", 429*6278ae03SDaniel P. Berrange "aes", 256, "xts", "essiv", "sha256", "sha1"), 430*6278ae03SDaniel P. Berrange 431*6278ae03SDaniel P. Berrange 432*6278ae03SDaniel P. Berrange # LUKS default but smaller key sizes 433*6278ae03SDaniel P. Berrange LUKSConfig("aes-128-xts-plain64-sha256-sha1", 434*6278ae03SDaniel P. Berrange "aes", 128, "xts", "plain64", None, "sha1"), 435*6278ae03SDaniel P. Berrange LUKSConfig("aes-192-xts-plain64-sha256-sha1", 436*6278ae03SDaniel P. Berrange "aes", 192, "xts", "plain64", None, "sha1"), 437*6278ae03SDaniel P. Berrange 438*6278ae03SDaniel P. Berrange LUKSConfig("twofish-128-xts-plain64-sha1", 439*6278ae03SDaniel P. Berrange "twofish", 128, "xts", "plain64", None, "sha1"), 440*6278ae03SDaniel P. Berrange LUKSConfig("twofish-192-xts-plain64-sha1", 441*6278ae03SDaniel P. Berrange "twofish", 192, "xts", "plain64", None, "sha1"), 442*6278ae03SDaniel P. Berrange 443*6278ae03SDaniel P. Berrange LUKSConfig("serpent-128-xts-plain64-sha1", 444*6278ae03SDaniel P. Berrange "serpent", 128, "xts", "plain64", None, "sha1"), 445*6278ae03SDaniel P. Berrange LUKSConfig("serpent-192-xts-plain64-sha1", 446*6278ae03SDaniel P. Berrange "serpent", 192, "xts", "plain64", None, "sha1"), 447*6278ae03SDaniel P. Berrange 448*6278ae03SDaniel P. Berrange LUKSConfig("cast6-128-xts-plain64-sha1", 449*6278ae03SDaniel P. Berrange "cast6", 128, "xts", "plain", None, "sha1"), 450*6278ae03SDaniel P. Berrange LUKSConfig("cast6-192-xts-plain64-sha1", 451*6278ae03SDaniel P. Berrange "cast6", 192, "xts", "plain64", None, "sha1"), 452*6278ae03SDaniel P. Berrange 453*6278ae03SDaniel P. Berrange 454*6278ae03SDaniel P. Berrange # LUKS default but diff hash 455*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha256", 456*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha256"), 457*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-sha512", 458*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "sha512"), 459*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain64-ripemd160", 460*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain64", None, "ripemd160"), 461*6278ae03SDaniel P. Berrange 462*6278ae03SDaniel P. Berrange # Password in slot 3 463*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwslot3", 464*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 465*6278ae03SDaniel P. Berrange passwords={ 466*6278ae03SDaniel P. Berrange "3": "slot3", 467*6278ae03SDaniel P. Berrange }), 468*6278ae03SDaniel P. Berrange 469*6278ae03SDaniel P. Berrange # Passwords in every slot 470*6278ae03SDaniel P. Berrange LUKSConfig("aes-256-xts-plain-sha1-pwallslots", 471*6278ae03SDaniel P. Berrange "aes", 256, "xts", "plain", None, "sha1", 472*6278ae03SDaniel P. Berrange passwords={ 473*6278ae03SDaniel P. Berrange "0": "slot1", 474*6278ae03SDaniel P. Berrange "1": "slot1", 475*6278ae03SDaniel P. Berrange "2": "slot2", 476*6278ae03SDaniel P. Berrange "3": "slot3", 477*6278ae03SDaniel P. Berrange "4": "slot4", 478*6278ae03SDaniel P. Berrange "5": "slot5", 479*6278ae03SDaniel P. Berrange "6": "slot6", 480*6278ae03SDaniel P. Berrange "7": "slot7", 481*6278ae03SDaniel P. Berrange }), 482*6278ae03SDaniel P. Berrange] 483*6278ae03SDaniel P. Berrange 484*6278ae03SDaniel P. Berrangeblacklist = [ 485*6278ae03SDaniel P. Berrange # We don't have a cast-6 cipher impl for QEMU yet 486*6278ae03SDaniel P. Berrange "cast6-256-xts-plain64-sha1", 487*6278ae03SDaniel P. Berrange "cast6-128-xts-plain64-sha1", 488*6278ae03SDaniel P. Berrange "cast6-192-xts-plain64-sha1", 489*6278ae03SDaniel P. Berrange 490*6278ae03SDaniel P. Berrange # GCrypt doesn't support Twofish with 192 bit key 491*6278ae03SDaniel P. Berrange "twofish-192-xts-plain64-sha1", 492*6278ae03SDaniel P. Berrange 493*6278ae03SDaniel P. Berrange # We don't have sha512 hash wired up yet 494*6278ae03SDaniel P. Berrange "aes-256-xts-plain64-sha512", 495*6278ae03SDaniel P. Berrange 496*6278ae03SDaniel P. Berrange # We don't have ripemd160 hash wired up yet 497*6278ae03SDaniel P. Berrange "aes-256-xts-plain64-ripemd160", 498*6278ae03SDaniel P. Berrange] 499*6278ae03SDaniel P. Berrange 500*6278ae03SDaniel P. Berrangewhitelist = [] 501*6278ae03SDaniel P. Berrangeif "LUKS_CONFIG" in os.environ: 502*6278ae03SDaniel P. Berrange whitelist = os.environ["LUKS_CONFIG"].split(",") 503*6278ae03SDaniel P. Berrange 504*6278ae03SDaniel P. Berrangefor config in configs: 505*6278ae03SDaniel P. Berrange if config.name in blacklist: 506*6278ae03SDaniel P. Berrange iotests.log("Skipping %s in blacklist" % config.name) 507*6278ae03SDaniel P. Berrange continue 508*6278ae03SDaniel P. Berrange 509*6278ae03SDaniel P. Berrange if len(whitelist) > 0 and config.name not in whitelist: 510*6278ae03SDaniel P. Berrange iotests.log("Skipping %s not in whitelist" % config.name) 511*6278ae03SDaniel P. Berrange continue 512*6278ae03SDaniel P. Berrange 513*6278ae03SDaniel P. Berrange test_once(config, qemu_img=False) 514*6278ae03SDaniel P. Berrange 515*6278ae03SDaniel P. Berrange # XXX we should support setting passwords in a non-0 516*6278ae03SDaniel P. Berrange # key slot with 'qemu-img create' in future 517*6278ae03SDaniel P. Berrange (pw, slot) = config.first_password() 518*6278ae03SDaniel P. Berrange if slot == "0": 519*6278ae03SDaniel P. Berrange test_once(config, qemu_img=True) 520