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