blob: d732a9020d5b5271c225f4329721614287ad157f [file] [log] [blame]
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001#
2# SPDX-License-Identifier: MIT
3#
4
5from oeqa.selftest.case import OESelftestTestCase
Patrick Williams45852732022-04-02 08:58:32 -05006from oeqa.utils.commands import runCmd, bitbake, get_bb_var
Andrew Geisslerd1e89492021-02-12 15:35:20 -06007import os
Andrew Geisslerd1e89492021-02-12 15:35:20 -06008import 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>;',
Andrew Geissler90fd73c2021-03-05 15:25:55 -060071 'default = "conf-1";',
72 'kernel = "kernel-1";',
73 'ramdisk = "ramdisk-1";'
Andrew Geisslerd1e89492021-02-12 15:35:20 -060074 ]
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"
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500116UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
117UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600118FIT_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 = [
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600140 ['/', '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'],
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600146 ]
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[:])
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600161 elif itspath and itspath[-1] == 'signature-1':
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600162 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"',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500176 'key-name-hint': '"img-oe-selftest"',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600177 }
178 reqsigvalues_config = {
179 'algo': '"sha256,rsa2048"',
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500180 'key-name-hint': '"cfg-oe-selftest"',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600181 'sign-images': '"kernel", "fdt"',
182 }
183
184 for itspath, values in sigs.items():
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600185 if 'conf-' in itspath:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600186 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()
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600213 self.assertIn('kernel-1', signed_sections)
214 self.assertIn('fdt-am335x-boneblack.dtb', signed_sections)
215 self.assertIn('conf-am335x-boneblack.dtb', signed_sections)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600216 for signed_section, values in signed_sections.items():
217 value = values.get('Sign algo', None)
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500218 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)
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600222 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
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500237 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"
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500272UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
273UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500274FIT_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"
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500355UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
356UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500357FIT_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"
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500600UBOOT_SIGN_IMG_KEYNAME = "img-oe-selftest"
601UBOOT_SIGN_KEYNAME = "cfg-oe-selftest"
Andrew Geissler3b8a17c2021-04-15 15:55:55 -0500602FIT_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
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600708 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"
Andrew Geissler615f2f12022-07-15 14:00:58 -0500741UBOOT_MKIMAGE_KERNEL_TYPE = "kernel"
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600742UBOOT_EXTLINUX = "0"
743FIT_GENERATE_KEYS = "1"
744KERNEL_IMAGETYPE_REPLACEMENT = "zImage"
Andrew Geisslereff27472021-10-29 15:35:00 -0500745FIT_KERNEL_COMP_ALG = "none"
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600746FIT_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'))
Andrew Geissler615f2f12022-07-15 14:00:58 -0500767 kernel_type = str(get_bb_var('UBOOT_MKIMAGE_KERNEL_TYPE'))
Andrew Geisslereff27472021-10-29 15:35:00 -0500768 kernel_compression = str(get_bb_var('FIT_KERNEL_COMP_ALG'))
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600769 uboot_arch = str(get_bb_var('UBOOT_ARCH'))
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600770 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 = [
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600777 'kernel-1 {',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600778 'description = "Linux kernel";',
Andrew Geisslereff27472021-10-29 15:35:00 -0500779 'data = /incbin/("linux.bin");',
Andrew Geissler615f2f12022-07-15 14:00:58 -0500780 'type = "' + kernel_type + '";',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600781 'arch = "' + uboot_arch + '";',
782 'os = "linux";',
Andrew Geisslereff27472021-10-29 15:35:00 -0500783 'compression = "' + kernel_compression + '";',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600784 'load = <' + kernel_load + '>;',
785 'entry = <' + kernel_entry + '>;',
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600786 'hash-1 {',
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600787 '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
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600806 rx_configs = re.compile("^conf-.*")
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600807 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
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600827 if 'kernel = "kernel-1";' not in node:
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600828 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")