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