1# 2# SPDX-License-Identifier: MIT 3# 4 5from oeqa.selftest.case import OESelftestTestCase 6from oeqa.utils.commands import runCmd, bitbake, get_bb_var 7import os 8import re 9 10class FitImageTests(OESelftestTestCase): 11 12 def test_fit_image(self): 13 """ 14 Summary: Check if FIT image and Image Tree Source (its) are built 15 and the Image Tree Source has the correct fields. 16 Expected: 1. fitImage and fitImage-its can be built 17 2. The type, load address, entrypoint address and 18 default values of kernel and ramdisk are as expected 19 in the Image Tree Source. Not all the fields are tested, 20 only the key fields that wont vary between different 21 architectures. 22 Product: oe-core 23 Author: Usama Arif <usama.arif@arm.com> 24 """ 25 config = """ 26# Enable creation of fitImage 27KERNEL_IMAGETYPE = "Image" 28KERNEL_IMAGETYPES += " fitImage " 29KERNEL_CLASSES = " kernel-fitimage " 30 31# RAM disk variables including load address and entrypoint for kernel and RAM disk 32IMAGE_FSTYPES += "cpio.gz" 33INITRAMFS_IMAGE = "core-image-minimal" 34UBOOT_RD_LOADADDRESS = "0x88000000" 35UBOOT_RD_ENTRYPOINT = "0x88000000" 36UBOOT_LOADADDRESS = "0x80080000" 37UBOOT_ENTRYPOINT = "0x80080000" 38FIT_DESC = "A model description" 39""" 40 self.write_config(config) 41 42 # fitImage is created as part of linux recipe 43 bitbake("virtual/kernel") 44 45 image_type = "core-image-minimal" 46 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 47 machine = get_bb_var('MACHINE') 48 fitimage_its_path = os.path.join(deploy_dir_image, 49 "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) 50 fitimage_path = os.path.join(deploy_dir_image, 51 "fitImage-%s-%s-%s" % (image_type, machine, machine)) 52 53 self.assertTrue(os.path.exists(fitimage_its_path), 54 "%s image tree source doesn't exist" % (fitimage_its_path)) 55 self.assertTrue(os.path.exists(fitimage_path), 56 "%s FIT image doesn't exist" % (fitimage_path)) 57 58 # Check that the type, load address, entrypoint address and default 59 # values for kernel and ramdisk in Image Tree Source are as expected. 60 # The order of fields in the below array is important. Not all the 61 # fields are tested, only the key fields that wont vary between 62 # different architectures. 63 its_field_check = [ 64 'description = "A model description";', 65 'type = "kernel";', 66 'load = <0x80080000>;', 67 'entry = <0x80080000>;', 68 'type = "ramdisk";', 69 'load = <0x88000000>;', 70 'entry = <0x88000000>;', 71 'default = "conf-1";', 72 'kernel = "kernel-1";', 73 'ramdisk = "ramdisk-1";' 74 ] 75 76 with open(fitimage_its_path) as its_file: 77 field_index = 0 78 for line in its_file: 79 if field_index == len(its_field_check): 80 break 81 if its_field_check[field_index] in line: 82 field_index +=1 83 84 if field_index != len(its_field_check): # if its equal, the test passed 85 self.assertTrue(field_index == len(its_field_check), 86 "Fields in Image Tree Source File %s did not match, error in finding %s" 87 % (fitimage_its_path, its_field_check[field_index])) 88 89 90 def test_sign_fit_image(self): 91 """ 92 Summary: Check if FIT image and Image Tree Source (its) are created 93 and signed correctly. 94 Expected: 1) its and FIT image are built successfully 95 2) Scanning the its file indicates signing is enabled 96 as requested by UBOOT_SIGN_ENABLE (using keys generated 97 via FIT_GENERATE_KEYS) 98 3) Dumping the FIT image indicates signature values 99 are present (including for images as enabled via 100 FIT_SIGN_INDIVIDUAL) 101 4) Examination of the do_assemble_fitimage runfile/logfile 102 indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN and 103 UBOOT_MKIMAGE_SIGN_ARGS are working as expected. 104 Product: oe-core 105 Author: Paul Eggleton <paul.eggleton@microsoft.com> based upon 106 work by Usama Arif <usama.arif@arm.com> 107 """ 108 config = """ 109# Enable creation of fitImage 110MACHINE = "beaglebone-yocto" 111KERNEL_IMAGETYPES += " fitImage " 112KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 113UBOOT_SIGN_ENABLE = "1" 114FIT_GENERATE_KEYS = "1" 115UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 116UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 117UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 118FIT_SIGN_INDIVIDUAL = "1" 119UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'" 120""" 121 self.write_config(config) 122 123 # fitImage is created as part of linux recipe 124 bitbake("virtual/kernel") 125 126 image_type = "core-image-minimal" 127 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 128 machine = get_bb_var('MACHINE') 129 fitimage_its_path = os.path.join(deploy_dir_image, 130 "fitImage-its-%s" % (machine,)) 131 fitimage_path = os.path.join(deploy_dir_image, 132 "fitImage-%s.bin" % (machine,)) 133 134 self.assertTrue(os.path.exists(fitimage_its_path), 135 "%s image tree source doesn't exist" % (fitimage_its_path)) 136 self.assertTrue(os.path.exists(fitimage_path), 137 "%s FIT image doesn't exist" % (fitimage_path)) 138 139 req_itspaths = [ 140 ['/', 'images', 'kernel-1'], 141 ['/', 'images', 'kernel-1', 'signature-1'], 142 ['/', 'images', 'fdt-am335x-boneblack.dtb'], 143 ['/', 'images', 'fdt-am335x-boneblack.dtb', 'signature-1'], 144 ['/', 'configurations', 'conf-am335x-boneblack.dtb'], 145 ['/', 'configurations', 'conf-am335x-boneblack.dtb', 'signature-1'], 146 ] 147 148 itspath = [] 149 itspaths = [] 150 linect = 0 151 sigs = {} 152 with open(fitimage_its_path) as its_file: 153 linect += 1 154 for line in its_file: 155 line = line.strip() 156 if line.endswith('};'): 157 itspath.pop() 158 elif line.endswith('{'): 159 itspath.append(line[:-1].strip()) 160 itspaths.append(itspath[:]) 161 elif itspath and itspath[-1] == 'signature-1': 162 itsdotpath = '.'.join(itspath) 163 if not itsdotpath in sigs: 164 sigs[itsdotpath] = {} 165 if not '=' in line or not line.endswith(';'): 166 self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 167 key, value = line.split('=', 1) 168 sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 169 170 for reqpath in req_itspaths: 171 if not reqpath in itspaths: 172 self.fail('Missing section in its file: %s' % reqpath) 173 174 reqsigvalues_image = { 175 'algo': '"sha256,rsa2048"', 176 'key-name-hint': '"img-oe-selftest"', 177 } 178 reqsigvalues_config = { 179 'algo': '"sha256,rsa2048"', 180 'key-name-hint': '"cfg-oe-selftest"', 181 'sign-images': '"kernel", "fdt"', 182 } 183 184 for itspath, values in sigs.items(): 185 if 'conf-' in itspath: 186 reqsigvalues = reqsigvalues_config 187 else: 188 reqsigvalues = reqsigvalues_image 189 for reqkey, reqvalue in reqsigvalues.items(): 190 value = values.get(reqkey, None) 191 if value is None: 192 self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 193 self.assertEqual(value, reqvalue) 194 195 # Dump the image to see if it really got signed 196 bitbake("u-boot-tools-native -c addto_recipe_sysroot") 197 result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 198 recipe_sysroot_native = result.output.split('=')[1].strip('"') 199 dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 200 result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 201 in_signed = None 202 signed_sections = {} 203 for line in result.output.splitlines(): 204 if line.startswith((' Configuration', ' Image')): 205 in_signed = re.search('\((.*)\)', line).groups()[0] 206 elif re.match('^ *', line) in (' ', ''): 207 in_signed = None 208 elif in_signed: 209 if not in_signed in signed_sections: 210 signed_sections[in_signed] = {} 211 key, value = line.split(':', 1) 212 signed_sections[in_signed][key.strip()] = value.strip() 213 self.assertIn('kernel-1', signed_sections) 214 self.assertIn('fdt-am335x-boneblack.dtb', signed_sections) 215 self.assertIn('conf-am335x-boneblack.dtb', signed_sections) 216 for signed_section, values in signed_sections.items(): 217 value = values.get('Sign algo', None) 218 if signed_section.startswith("conf"): 219 self.assertEqual(value, 'sha256,rsa2048:cfg-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 220 else: 221 self.assertEqual(value, 'sha256,rsa2048:img-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 222 value = values.get('Sign value', None) 223 self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 224 225 # Check for UBOOT_MKIMAGE_SIGN_ARGS 226 result = runCmd('bitbake -e virtual/kernel | grep ^T=') 227 tempdir = result.output.split('=', 1)[1].strip().strip('') 228 result = runCmd('grep "a smart comment" %s/run.do_assemble_fitimage' % tempdir, ignore_status=True) 229 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN_ARGS value did not get used') 230 231 # Check for evidence of test-mkimage-wrapper class 232 result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) 233 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 234 result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True) 235 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 236 237 def test_uboot_fit_image(self): 238 """ 239 Summary: Check if Uboot FIT image and Image Tree Source 240 (its) are built and the Image Tree Source has the 241 correct fields. 242 Expected: 1. u-boot-fitImage and u-boot-its can be built 243 2. The type, load address, entrypoint address and 244 default values of U-boot image are correct in the 245 Image Tree Source. Not all the fields are tested, 246 only the key fields that wont vary between 247 different architectures. 248 Product: oe-core 249 Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> 250 based on work by Usama Arif <usama.arif@arm.com> 251 """ 252 config = """ 253# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 254MACHINE = "qemuarm" 255UBOOT_MACHINE = "am57xx_evm_defconfig" 256SPL_BINARY = "MLO" 257 258# Enable creation of the U-Boot fitImage 259UBOOT_FITIMAGE_ENABLE = "1" 260 261# (U-boot) fitImage properties 262UBOOT_LOADADDRESS = "0x80080000" 263UBOOT_ENTRYPOINT = "0x80080000" 264UBOOT_FIT_DESC = "A model description" 265 266# Enable creation of Kernel fitImage 267KERNEL_IMAGETYPES += " fitImage " 268KERNEL_CLASSES = " kernel-fitimage" 269UBOOT_SIGN_ENABLE = "1" 270FIT_GENERATE_KEYS = "1" 271UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 272UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 273UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 274FIT_SIGN_INDIVIDUAL = "1" 275""" 276 self.write_config(config) 277 278 # The U-Boot fitImage is created as part of linux recipe 279 bitbake("virtual/kernel") 280 281 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 282 machine = get_bb_var('MACHINE') 283 fitimage_its_path = os.path.join(deploy_dir_image, 284 "u-boot-its-%s" % (machine,)) 285 fitimage_path = os.path.join(deploy_dir_image, 286 "u-boot-fitImage-%s" % (machine,)) 287 288 self.assertTrue(os.path.exists(fitimage_its_path), 289 "%s image tree source doesn't exist" % (fitimage_its_path)) 290 self.assertTrue(os.path.exists(fitimage_path), 291 "%s FIT image doesn't exist" % (fitimage_path)) 292 293 # Check that the type, load address, entrypoint address and default 294 # values for kernel and ramdisk in Image Tree Source are as expected. 295 # The order of fields in the below array is important. Not all the 296 # fields are tested, only the key fields that wont vary between 297 # different architectures. 298 its_field_check = [ 299 'description = "A model description";', 300 'type = "standalone";', 301 'load = <0x80080000>;', 302 'entry = <0x80080000>;', 303 'default = "conf";', 304 'loadables = "uboot";', 305 'fdt = "fdt";' 306 ] 307 308 with open(fitimage_its_path) as its_file: 309 field_index = 0 310 for line in its_file: 311 if field_index == len(its_field_check): 312 break 313 if its_field_check[field_index] in line: 314 field_index +=1 315 316 if field_index != len(its_field_check): # if its equal, the test passed 317 self.assertTrue(field_index == len(its_field_check), 318 "Fields in Image Tree Source File %s did not match, error in finding %s" 319 % (fitimage_its_path, its_field_check[field_index])) 320 321 def test_uboot_sign_fit_image(self): 322 """ 323 Summary: Check if Uboot FIT image and Image Tree Source 324 (its) are built and the Image Tree Source has the 325 correct fields, in the scenario where the Kernel 326 is also creating/signing it's fitImage. 327 Expected: 1. u-boot-fitImage and u-boot-its can be built 328 2. The type, load address, entrypoint address and 329 default values of U-boot image are correct in the 330 Image Tree Source. Not all the fields are tested, 331 only the key fields that wont vary between 332 different architectures. 333 Product: oe-core 334 Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> 335 based on work by Usama Arif <usama.arif@arm.com> 336 """ 337 config = """ 338# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 339MACHINE = "qemuarm" 340UBOOT_MACHINE = "am57xx_evm_defconfig" 341SPL_BINARY = "MLO" 342 343# Enable creation of the U-Boot fitImage 344UBOOT_FITIMAGE_ENABLE = "1" 345 346# (U-boot) fitImage properties 347UBOOT_LOADADDRESS = "0x80080000" 348UBOOT_ENTRYPOINT = "0x80080000" 349UBOOT_FIT_DESC = "A model description" 350KERNEL_IMAGETYPES += " fitImage " 351KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 352UBOOT_SIGN_ENABLE = "1" 353FIT_GENERATE_KEYS = "1" 354UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 355UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 356UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 357FIT_SIGN_INDIVIDUAL = "1" 358UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" 359""" 360 self.write_config(config) 361 362 # The U-Boot fitImage is created as part of linux recipe 363 bitbake("virtual/kernel") 364 365 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 366 machine = get_bb_var('MACHINE') 367 fitimage_its_path = os.path.join(deploy_dir_image, 368 "u-boot-its-%s" % (machine,)) 369 fitimage_path = os.path.join(deploy_dir_image, 370 "u-boot-fitImage-%s" % (machine,)) 371 372 self.assertTrue(os.path.exists(fitimage_its_path), 373 "%s image tree source doesn't exist" % (fitimage_its_path)) 374 self.assertTrue(os.path.exists(fitimage_path), 375 "%s FIT image doesn't exist" % (fitimage_path)) 376 377 # Check that the type, load address, entrypoint address and default 378 # values for kernel and ramdisk in Image Tree Source are as expected. 379 # The order of fields in the below array is important. Not all the 380 # fields are tested, only the key fields that wont vary between 381 # different architectures. 382 its_field_check = [ 383 'description = "A model description";', 384 'type = "standalone";', 385 'load = <0x80080000>;', 386 'entry = <0x80080000>;', 387 'default = "conf";', 388 'loadables = "uboot";', 389 'fdt = "fdt";' 390 ] 391 392 with open(fitimage_its_path) as its_file: 393 field_index = 0 394 for line in its_file: 395 if field_index == len(its_field_check): 396 break 397 if its_field_check[field_index] in line: 398 field_index +=1 399 400 if field_index != len(its_field_check): # if its equal, the test passed 401 self.assertTrue(field_index == len(its_field_check), 402 "Fields in Image Tree Source File %s did not match, error in finding %s" 403 % (fitimage_its_path, its_field_check[field_index])) 404 405 406 def test_sign_standalone_uboot_fit_image(self): 407 """ 408 Summary: Check if U-Boot FIT image and Image Tree Source (its) are 409 created and signed correctly for the scenario where only 410 the U-Boot proper fitImage is being created and signed. 411 Expected: 1) U-Boot its and FIT image are built successfully 412 2) Scanning the its file indicates signing is enabled 413 as requested by SPL_SIGN_ENABLE (using keys generated 414 via UBOOT_FIT_GENERATE_KEYS) 415 3) Dumping the FIT image indicates signature values 416 are present 417 4) Examination of the do_uboot_assemble_fitimage 418 runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN 419 and SPL_MKIMAGE_SIGN_ARGS are working as expected. 420 Product: oe-core 421 Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon 422 work by Paul Eggleton <paul.eggleton@microsoft.com> and 423 Usama Arif <usama.arif@arm.com> 424 """ 425 config = """ 426# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at 427# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 428MACHINE = "qemuarm" 429UBOOT_MACHINE = "am57xx_evm_defconfig" 430SPL_BINARY = "MLO" 431# The kernel-fitimage class is a dependency even if we're only 432# creating/signing the U-Boot fitImage 433KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 434# Enable creation and signing of the U-Boot fitImage 435UBOOT_FITIMAGE_ENABLE = "1" 436SPL_SIGN_ENABLE = "1" 437SPL_SIGN_KEYNAME = "spl-oe-selftest" 438SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 439UBOOT_DTB_BINARY = "u-boot.dtb" 440UBOOT_ENTRYPOINT = "0x80000000" 441UBOOT_LOADADDRESS = "0x80000000" 442UBOOT_DTB_LOADADDRESS = "0x82000000" 443UBOOT_ARCH = "arm" 444SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 445SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'" 446UBOOT_EXTLINUX = "0" 447UBOOT_FIT_GENERATE_KEYS = "1" 448UBOOT_FIT_HASH_ALG = "sha256" 449""" 450 self.write_config(config) 451 452 # The U-Boot fitImage is created as part of linux recipe 453 bitbake("virtual/kernel") 454 455 image_type = "core-image-minimal" 456 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 457 machine = get_bb_var('MACHINE') 458 fitimage_its_path = os.path.join(deploy_dir_image, 459 "u-boot-its-%s" % (machine,)) 460 fitimage_path = os.path.join(deploy_dir_image, 461 "u-boot-fitImage-%s" % (machine,)) 462 463 self.assertTrue(os.path.exists(fitimage_its_path), 464 "%s image tree source doesn't exist" % (fitimage_its_path)) 465 self.assertTrue(os.path.exists(fitimage_path), 466 "%s FIT image doesn't exist" % (fitimage_path)) 467 468 req_itspaths = [ 469 ['/', 'images', 'uboot'], 470 ['/', 'images', 'uboot', 'signature'], 471 ['/', 'images', 'fdt'], 472 ['/', 'images', 'fdt', 'signature'], 473 ] 474 475 itspath = [] 476 itspaths = [] 477 linect = 0 478 sigs = {} 479 with open(fitimage_its_path) as its_file: 480 linect += 1 481 for line in its_file: 482 line = line.strip() 483 if line.endswith('};'): 484 itspath.pop() 485 elif line.endswith('{'): 486 itspath.append(line[:-1].strip()) 487 itspaths.append(itspath[:]) 488 elif itspath and itspath[-1] == 'signature': 489 itsdotpath = '.'.join(itspath) 490 if not itsdotpath in sigs: 491 sigs[itsdotpath] = {} 492 if not '=' in line or not line.endswith(';'): 493 self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 494 key, value = line.split('=', 1) 495 sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 496 497 for reqpath in req_itspaths: 498 if not reqpath in itspaths: 499 self.fail('Missing section in its file: %s' % reqpath) 500 501 reqsigvalues_image = { 502 'algo': '"sha256,rsa2048"', 503 'key-name-hint': '"spl-oe-selftest"', 504 } 505 506 for itspath, values in sigs.items(): 507 reqsigvalues = reqsigvalues_image 508 for reqkey, reqvalue in reqsigvalues.items(): 509 value = values.get(reqkey, None) 510 if value is None: 511 self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 512 self.assertEqual(value, reqvalue) 513 514 # Dump the image to see if it really got signed 515 bitbake("u-boot-tools-native -c addto_recipe_sysroot") 516 result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 517 recipe_sysroot_native = result.output.split('=')[1].strip('"') 518 dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 519 result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 520 in_signed = None 521 signed_sections = {} 522 for line in result.output.splitlines(): 523 if line.startswith((' Image')): 524 in_signed = re.search('\((.*)\)', line).groups()[0] 525 elif re.match(' \w', line): 526 in_signed = None 527 elif in_signed: 528 if not in_signed in signed_sections: 529 signed_sections[in_signed] = {} 530 key, value = line.split(':', 1) 531 signed_sections[in_signed][key.strip()] = value.strip() 532 self.assertIn('uboot', signed_sections) 533 self.assertIn('fdt', signed_sections) 534 for signed_section, values in signed_sections.items(): 535 value = values.get('Sign algo', None) 536 self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 537 value = values.get('Sign value', None) 538 self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 539 540 # Check for SPL_MKIMAGE_SIGN_ARGS 541 result = runCmd('bitbake -e virtual/kernel | grep ^T=') 542 tempdir = result.output.split('=', 1)[1].strip().strip('') 543 result = runCmd('grep "a smart U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 544 self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') 545 546 # Check for evidence of test-mkimage-wrapper class 547 result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 548 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 549 result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 550 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 551 552 def test_sign_cascaded_uboot_fit_image(self): 553 """ 554 Summary: Check if U-Boot FIT image and Image Tree Source (its) are 555 created and signed correctly for the scenario where both 556 U-Boot proper and Kernel fitImages are being created and 557 signed. 558 Expected: 1) U-Boot its and FIT image are built successfully 559 2) Scanning the its file indicates signing is enabled 560 as requested by SPL_SIGN_ENABLE (using keys generated 561 via UBOOT_FIT_GENERATE_KEYS) 562 3) Dumping the FIT image indicates signature values 563 are present 564 4) Examination of the do_uboot_assemble_fitimage 565 runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN 566 and SPL_MKIMAGE_SIGN_ARGS are working as expected. 567 Product: oe-core 568 Author: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon 569 work by Paul Eggleton <paul.eggleton@microsoft.com> and 570 Usama Arif <usama.arif@arm.com> 571 """ 572 config = """ 573# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at 574# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set 575MACHINE = "qemuarm" 576UBOOT_MACHINE = "am57xx_evm_defconfig" 577SPL_BINARY = "MLO" 578# Enable creation and signing of the U-Boot fitImage 579UBOOT_FITIMAGE_ENABLE = "1" 580SPL_SIGN_ENABLE = "1" 581SPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest" 582SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 583UBOOT_DTB_BINARY = "u-boot.dtb" 584UBOOT_ENTRYPOINT = "0x80000000" 585UBOOT_LOADADDRESS = "0x80000000" 586UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 587UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'" 588UBOOT_DTB_LOADADDRESS = "0x82000000" 589UBOOT_ARCH = "arm" 590SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 591SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'" 592UBOOT_EXTLINUX = "0" 593UBOOT_FIT_GENERATE_KEYS = "1" 594UBOOT_FIT_HASH_ALG = "sha256" 595KERNEL_IMAGETYPES += " fitImage " 596KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper " 597UBOOT_SIGN_ENABLE = "1" 598FIT_GENERATE_KEYS = "1" 599UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys" 600UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest" 601UBOOT_SIGN_KEYNAME = "cfg-oe-selftest" 602FIT_SIGN_INDIVIDUAL = "1" 603""" 604 self.write_config(config) 605 606 # The U-Boot fitImage is created as part of linux recipe 607 bitbake("virtual/kernel") 608 609 image_type = "core-image-minimal" 610 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 611 machine = get_bb_var('MACHINE') 612 fitimage_its_path = os.path.join(deploy_dir_image, 613 "u-boot-its-%s" % (machine,)) 614 fitimage_path = os.path.join(deploy_dir_image, 615 "u-boot-fitImage-%s" % (machine,)) 616 617 self.assertTrue(os.path.exists(fitimage_its_path), 618 "%s image tree source doesn't exist" % (fitimage_its_path)) 619 self.assertTrue(os.path.exists(fitimage_path), 620 "%s FIT image doesn't exist" % (fitimage_path)) 621 622 req_itspaths = [ 623 ['/', 'images', 'uboot'], 624 ['/', 'images', 'uboot', 'signature'], 625 ['/', 'images', 'fdt'], 626 ['/', 'images', 'fdt', 'signature'], 627 ] 628 629 itspath = [] 630 itspaths = [] 631 linect = 0 632 sigs = {} 633 with open(fitimage_its_path) as its_file: 634 linect += 1 635 for line in its_file: 636 line = line.strip() 637 if line.endswith('};'): 638 itspath.pop() 639 elif line.endswith('{'): 640 itspath.append(line[:-1].strip()) 641 itspaths.append(itspath[:]) 642 elif itspath and itspath[-1] == 'signature': 643 itsdotpath = '.'.join(itspath) 644 if not itsdotpath in sigs: 645 sigs[itsdotpath] = {} 646 if not '=' in line or not line.endswith(';'): 647 self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line)) 648 key, value = line.split('=', 1) 649 sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';') 650 651 for reqpath in req_itspaths: 652 if not reqpath in itspaths: 653 self.fail('Missing section in its file: %s' % reqpath) 654 655 reqsigvalues_image = { 656 'algo': '"sha256,rsa2048"', 657 'key-name-hint': '"spl-cascaded-oe-selftest"', 658 } 659 660 for itspath, values in sigs.items(): 661 reqsigvalues = reqsigvalues_image 662 for reqkey, reqvalue in reqsigvalues.items(): 663 value = values.get(reqkey, None) 664 if value is None: 665 self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath)) 666 self.assertEqual(value, reqvalue) 667 668 # Dump the image to see if it really got signed 669 bitbake("u-boot-tools-native -c addto_recipe_sysroot") 670 result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=') 671 recipe_sysroot_native = result.output.split('=')[1].strip('"') 672 dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage') 673 result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path)) 674 in_signed = None 675 signed_sections = {} 676 for line in result.output.splitlines(): 677 if line.startswith((' Image')): 678 in_signed = re.search('\((.*)\)', line).groups()[0] 679 elif re.match(' \w', line): 680 in_signed = None 681 elif in_signed: 682 if not in_signed in signed_sections: 683 signed_sections[in_signed] = {} 684 key, value = line.split(':', 1) 685 signed_sections[in_signed][key.strip()] = value.strip() 686 self.assertIn('uboot', signed_sections) 687 self.assertIn('fdt', signed_sections) 688 for signed_section, values in signed_sections.items(): 689 value = values.get('Sign algo', None) 690 self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section) 691 value = values.get('Sign value', None) 692 self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section) 693 694 # Check for SPL_MKIMAGE_SIGN_ARGS 695 result = runCmd('bitbake -e virtual/kernel | grep ^T=') 696 tempdir = result.output.split('=', 1)[1].strip().strip('') 697 result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 698 self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used') 699 700 # Check for evidence of test-mkimage-wrapper class 701 result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 702 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work') 703 result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True) 704 self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work') 705 706 707 708 def test_initramfs_bundle(self): 709 """ 710 Summary: Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its) 711 The FIT settings are set by the test case. 712 The machine used is beaglebone-yocto. 713 Expected: 1. The ITS is generated with initramfs bundle support 714 2. All the fields in the kernel node are as expected (matching the 715 conf settings) 716 3. The kernel is included in all the available configurations and 717 its hash is included in the configuration signature 718 719 Product: oe-core 720 Author: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> 721 """ 722 723 config = """ 724DISTRO="poky" 725MACHINE = "beaglebone-yocto" 726INITRAMFS_IMAGE_BUNDLE = "1" 727INITRAMFS_IMAGE = "core-image-minimal-initramfs" 728INITRAMFS_SCRIPTS = "" 729UBOOT_MACHINE = "am335x_evm_defconfig" 730KERNEL_CLASSES = " kernel-fitimage " 731KERNEL_IMAGETYPES = "fitImage" 732UBOOT_SIGN_ENABLE = "1" 733UBOOT_SIGN_KEYNAME = "beaglebonekey" 734UBOOT_SIGN_KEYDIR ?= "${DEPLOY_DIR_IMAGE}" 735UBOOT_DTB_BINARY = "u-boot.dtb" 736UBOOT_ENTRYPOINT = "0x80000000" 737UBOOT_LOADADDRESS = "0x80000000" 738UBOOT_DTB_LOADADDRESS = "0x82000000" 739UBOOT_ARCH = "arm" 740UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000" 741UBOOT_MKIMAGE_KERNEL_TYPE = "kernel" 742UBOOT_EXTLINUX = "0" 743FIT_GENERATE_KEYS = "1" 744KERNEL_IMAGETYPE_REPLACEMENT = "zImage" 745FIT_KERNEL_COMP_ALG = "none" 746FIT_HASH_ALG = "sha256" 747""" 748 self.write_config(config) 749 750 # fitImage is created as part of linux recipe 751 bitbake("virtual/kernel") 752 753 image_type = get_bb_var('INITRAMFS_IMAGE') 754 deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE') 755 machine = get_bb_var('MACHINE') 756 fitimage_its_path = os.path.join(deploy_dir_image, 757 "fitImage-its-%s-%s-%s" % (image_type, machine, machine)) 758 fitimage_path = os.path.join(deploy_dir_image,"fitImage") 759 760 self.assertTrue(os.path.exists(fitimage_its_path), 761 "%s image tree source doesn't exist" % (fitimage_its_path)) 762 self.assertTrue(os.path.exists(fitimage_path), 763 "%s FIT image doesn't exist" % (fitimage_path)) 764 765 kernel_load = str(get_bb_var('UBOOT_LOADADDRESS')) 766 kernel_entry = str(get_bb_var('UBOOT_ENTRYPOINT')) 767 kernel_type = str(get_bb_var('UBOOT_MKIMAGE_KERNEL_TYPE')) 768 kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG')) 769 uboot_arch = str(get_bb_var('UBOOT_ARCH')) 770 fit_hash_alg = str(get_bb_var('FIT_HASH_ALG')) 771 772 its_file = open(fitimage_its_path) 773 774 its_lines = [line.strip() for line in its_file.readlines()] 775 776 exp_node_lines = [ 777 'kernel-1 {', 778 'description = "Linux kernel";', 779 'data = /incbin/("linux.bin");', 780 'type = "' + kernel_type + '";', 781 'arch = "' + uboot_arch + '";', 782 'os = "linux";', 783 'compression = "' + kernel_compression + '";', 784 'load = <' + kernel_load + '>;', 785 'entry = <' + kernel_entry + '>;', 786 'hash-1 {', 787 'algo = "' + fit_hash_alg +'";', 788 '};', 789 '};' 790 ] 791 792 node_str = exp_node_lines[0] 793 794 test_passed = False 795 796 print ("checking kernel node\n") 797 798 if node_str in its_lines: 799 node_start_idx = its_lines.index(node_str) 800 node = its_lines[node_start_idx:(node_start_idx + len(exp_node_lines))] 801 if node == exp_node_lines: 802 print("kernel node verified") 803 else: 804 self.assertTrue(test_passed == True,"kernel node does not match expectation") 805 806 rx_configs = re.compile("^conf-.*") 807 its_configs = list(filter(rx_configs.match, its_lines)) 808 809 for cfg_str in its_configs: 810 cfg_start_idx = its_lines.index(cfg_str) 811 line_idx = cfg_start_idx + 2 812 node_end = False 813 while node_end == False: 814 if its_lines[line_idx] == "};" and its_lines[line_idx-1] == "};" : 815 node_end = True 816 line_idx = line_idx + 1 817 818 node = its_lines[cfg_start_idx:line_idx] 819 print("checking configuration " + cfg_str.rstrip(" {")) 820 rx_desc_line = re.compile("^description.*1 Linux kernel.*") 821 if len(list(filter(rx_desc_line.match, node))) != 1: 822 self.assertTrue(test_passed == True,"kernel keyword not found in the description line") 823 break 824 else: 825 print("kernel keyword found in the description line") 826 827 if 'kernel = "kernel-1";' not in node: 828 self.assertTrue(test_passed == True,"kernel line not found") 829 break 830 else: 831 print("kernel line found") 832 833 rx_sign_line = re.compile("^sign-images.*kernel.*") 834 if len(list(filter(rx_sign_line.match, node))) != 1: 835 self.assertTrue(test_passed == True,"kernel hash not signed") 836 break 837 else: 838 print("kernel hash signed") 839 840 test_passed = True 841 self.assertTrue(test_passed == True,"Initramfs bundle test success") 842