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