colibri_imx6: fix video stdout in default environment
[oweals/u-boot.git] / doc / uImage.FIT / beaglebone_vboot.txt
1 Verified Boot on the Beaglebone Black
2 =====================================
3
4 Introduction
5 ------------
6
7 Before reading this, please read verified-boot.txt and signature.txt. These
8 instructions are for mainline U-Boot from v2014.07 onwards.
9
10 There is quite a bit of documentation in this directory describing how
11 verified boot works in U-Boot. There is also a test which runs through the
12 entire process of signing an image and running U-Boot (sandbox) to check it.
13 However, it might be useful to also have an example on a real board.
14
15 Beaglebone Black is a fairly common board so seems to be a reasonable choice
16 for an example of how to enable verified boot using U-Boot.
17
18 First a note that may to help avoid confusion. U-Boot and Linux both use
19 device tree. They may use the same device tree source, but it is seldom useful
20 for them to use the exact same binary from the same place. More typically,
21 U-Boot has its device tree packaged wtih it, and the kernel's device tree is
22 packaged with the kernel. In particular this is important with verified boot,
23 since U-Boot's device tree must be immutable. If it can be changed then the
24 public keys can be changed and verified boot is useless. An attacker can
25 simply generate a new key and put his public key into U-Boot so that
26 everything verifies. On the other hand the kernel's device tree typically
27 changes when the kernel changes, so it is useful to package an updated device
28 tree with the kernel binary. U-Boot supports the latter with its flexible FIT
29 format (Flat Image Tree).
30
31
32 Overview
33 --------
34
35 The steps are roughly as follows:
36
37 1. Build U-Boot for the board, with the verified boot options enabled.
38
39 2. Obtain a suitable Linux kernel
40
41 3. Create a Image Tree Source file (ITS) file describing how you want the
42 kernel to be packaged, compressed and signed.
43
44 4. Create a key pair
45
46 5. Sign the kernel
47
48 6. Put the public key into U-Boot's image
49
50 7. Put U-Boot and the kernel onto the board
51
52 8. Try it
53
54
55 Step 1: Build U-Boot
56 --------------------
57
58 a. Set up the environment variable to point to your toolchain. You will need
59 this for U-Boot and also for the kernel if you build it. For example if you
60 installed a Linaro version manually it might be something like:
61
62    export CROSS_COMPILE=/opt/linaro/gcc-linaro-arm-linux-gnueabihf-4.8-2013.08_linux/bin/arm-linux-gnueabihf-
63
64 or if you just installed gcc-arm-linux-gnueabi then it might be
65
66    export CROSS_COMPILE=arm-linux-gnueabi-
67
68 b. Configure and build U-Boot with verified boot enabled:
69
70    export UBOOT=/path/to/u-boot
71    cd $UBOOT
72    # You can add -j10 if you have 10 CPUs to make it faster
73    make O=b/am335x_boneblack_vboot am335x_boneblack_vboot_config all
74    export UOUT=$UBOOT/b/am335x_boneblack_vboot
75
76 c. You will now have a U-Boot image:
77
78    file b/am335x_boneblack_vboot/u-boot-dtb.img
79 b/am335x_boneblack_vboot/u-boot-dtb.img: u-boot legacy uImage, U-Boot 2014.07-rc2-00065-g2f69f8, Firmware/ARM, Firmware Image (Not compressed), 395375 bytes, Sat May 31 16:19:04 2014, Load Address: 0x80800000, Entry Point: 0x00000000, Header CRC: 0x0ABD6ACA, Data CRC: 0x36DEF7E4
80
81
82 Step 2: Build Linux
83 --------------------
84
85 a. Find the kernel image ('Image') and device tree (.dtb) file you plan to
86 use. In our case it is am335x-boneblack.dtb and it is built with the kernel.
87 At the time of writing an SD Boot image can be obtained from here:
88
89    http://www.elinux.org/Beagleboard:Updating_The_Software#Image_For_Booting_From_microSD
90
91 You can write this to an SD card and then mount it to extract the kernel and
92 device tree files.
93
94 You can also build a kernel. Instructions for this are are here:
95
96    http://elinux.org/Building_BBB_Kernel
97
98 or you can use your favourite search engine. Following these instructions
99 produces a kernel Image and device tree files. For the record the steps were:
100
101    export KERNEL=/path/to/kernel
102    cd $KERNEL
103    git clone git://github.com/beagleboard/kernel.git .
104    git checkout v3.14
105    ./patch.sh
106    cp configs/beaglebone kernel/arch/arm/configs/beaglebone_defconfig
107    cd kernel
108    make beaglebone_defconfig
109    make uImage dtbs   # -j10 if you have 10 CPUs
110    export OKERNEL=$KERNEL/kernel/arch/arm/boot
111
112 c. You now have the 'Image' and 'am335x-boneblack.dtb' files needed to boot.
113
114
115 Step 3: Create the ITS
116 ----------------------
117
118 Set up a directory for your work.
119
120    export WORK=/path/to/dir
121    cd $WORK
122
123 Put this into a file in that directory called sign.its:
124
125 /dts-v1/;
126
127 / {
128         description = "Beaglebone black";
129         #address-cells = <1>;
130
131         images {
132                 kernel {
133                         data = /incbin/("Image.lzo");
134                         type = "kernel";
135                         arch = "arm";
136                         os = "linux";
137                         compression = "lzo";
138                         load = <0x80008000>;
139                         entry = <0x80008000>;
140                         hash-1 {
141                                 algo = "sha1";
142                         };
143                 };
144                 fdt-1 {
145                         description = "beaglebone-black";
146                         data = /incbin/("am335x-boneblack.dtb");
147                         type = "flat_dt";
148                         arch = "arm";
149                         compression = "none";
150                         hash-1 {
151                                 algo = "sha1";
152                         };
153                 };
154         };
155         configurations {
156                 default = "conf-1";
157                 conf-1 {
158                         kernel = "kernel";
159                         fdt = "fdt-1";
160                         signature-1 {
161                                 algo = "sha1,rsa2048";
162                                 key-name-hint = "dev";
163                                 sign-images = "fdt", "kernel";
164                         };
165                 };
166         };
167 };
168
169
170 The explanation for this is all in the documentation you have already read.
171 But briefly it packages a kernel and device tree, and provides a single
172 configuration to be signed with a key named 'dev'. The kernel is compressed
173 with LZO to make it smaller.
174
175
176 Step 4: Create a key pair
177 -------------------------
178
179 See signature.txt for details on this step.
180
181    cd $WORK
182    mkdir keys
183    openssl genrsa -F4 -out keys/dev.key 2048
184    openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt
185
186 Note: keys/dev.key contains your private key and is very secret. If anyone
187 gets access to that file they can sign kernels with it. Keep it secure.
188
189
190 Step 5: Sign the kernel
191 -----------------------
192
193 We need to use mkimage (which was built when you built U-Boot) to package the
194 Linux kernel into a FIT (Flat Image Tree, a flexible file format that U-Boot
195 can load) using the ITS file you just created.
196
197 At the same time we must put the public key into U-Boot device tree, with the
198 'required' property, which tells U-Boot that this key must be verified for the
199 image to be valid. You will make this key available to U-Boot for booting in
200 step 6.
201
202    ln -s $OKERNEL/dts/am335x-boneblack.dtb
203    ln -s $OKERNEL/Image
204    ln -s $UOUT/u-boot-dtb.img
205    cp $UOUT/arch/arm/dts/am335x-boneblack.dtb am335x-boneblack-pubkey.dtb
206    lzop Image
207    $UOUT/tools/mkimage -f sign.its -K am335x-boneblack-pubkey.dtb -k keys -r image.fit
208
209 You should see something like this:
210
211 FIT description: Beaglebone black
212 Created:         Sun Jun  1 12:50:30 2014
213  Image 0 (kernel)
214   Description:  unavailable
215   Created:      Sun Jun  1 12:50:30 2014
216   Type:         Kernel Image
217   Compression:  lzo compressed
218   Data Size:    7790938 Bytes = 7608.34 kB = 7.43 MB
219   Architecture: ARM
220   OS:           Linux
221   Load Address: 0x80008000
222   Entry Point:  0x80008000
223   Hash algo:    sha1
224   Hash value:   c94364646427e10f423837e559898ef02c97b988
225  Image 1 (fdt-1)
226   Description:  beaglebone-black
227   Created:      Sun Jun  1 12:50:30 2014
228   Type:         Flat Device Tree
229   Compression:  uncompressed
230   Data Size:    31547 Bytes = 30.81 kB = 0.03 MB
231   Architecture: ARM
232   Hash algo:    sha1
233   Hash value:   cb09202f889d824f23b8e4404b781be5ad38a68d
234  Default Configuration: 'conf-1'
235  Configuration 0 (conf-1)
236   Description:  unavailable
237   Kernel:       kernel
238   FDT:          fdt-1
239
240
241 Now am335x-boneblack-pubkey.dtb contains the public key and image.fit contains
242 the signed kernel. Jump to step 6 if you like, or continue reading to increase
243 your understanding.
244
245 You can also run fit_check_sign to check it:
246
247    $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb
248
249 which results in:
250
251 Verifying Hash Integrity ... sha1,rsa2048:dev+
252 ## Loading kernel from FIT Image at 7fc6ee469000 ...
253    Using 'conf-1' configuration
254    Verifying Hash Integrity ...
255 sha1,rsa2048:dev+
256 OK
257
258    Trying 'kernel' kernel subimage
259      Description:  unavailable
260      Created:      Sun Jun  1 12:50:30 2014
261      Type:         Kernel Image
262      Compression:  lzo compressed
263      Data Size:    7790938 Bytes = 7608.34 kB = 7.43 MB
264      Architecture: ARM
265      OS:           Linux
266      Load Address: 0x80008000
267      Entry Point:  0x80008000
268      Hash algo:    sha1
269      Hash value:   c94364646427e10f423837e559898ef02c97b988
270    Verifying Hash Integrity ...
271 sha1+
272 OK
273
274 Unimplemented compression type 4
275 ## Loading fdt from FIT Image at 7fc6ee469000 ...
276    Using 'conf-1' configuration
277    Trying 'fdt-1' fdt subimage
278      Description:  beaglebone-black
279      Created:      Sun Jun  1 12:50:30 2014
280      Type:         Flat Device Tree
281      Compression:  uncompressed
282      Data Size:    31547 Bytes = 30.81 kB = 0.03 MB
283      Architecture: ARM
284      Hash algo:    sha1
285      Hash value:   cb09202f889d824f23b8e4404b781be5ad38a68d
286    Verifying Hash Integrity ...
287 sha1+
288 OK
289
290    Loading Flat Device Tree ... OK
291
292 ## Loading ramdisk from FIT Image at 7fc6ee469000 ...
293    Using 'conf-1' configuration
294 Could not find subimage node
295
296 Signature check OK
297
298
299 At the top, you see "sha1,rsa2048:dev+". This means that it checked an RSA key
300 of size 2048 bits using SHA1 as the hash algorithm. The key name checked was
301 'dev' and the '+' means that it verified. If it showed '-' that would be bad.
302
303 Once the configuration is verified it is then possible to rely on the hashes
304 in each image referenced by that configuration. So fit_check_sign goes on to
305 load each of the images. We have a kernel and an FDT but no ramkdisk. In each
306 case fit_check_sign checks the hash and prints sha1+ meaning that the SHA1
307 hash verified. This means that none of the images has been tampered with.
308
309 There is a test in test/vboot which uses U-Boot's sandbox build to verify that
310 the above flow works.
311
312 But it is fun to do this by hand, so you can load image.fit into a hex editor
313 like ghex, and change a byte in the kernel:
314
315    $UOUT/tools/fit_info -f image.fit -n /images/kernel -p data
316 NAME: kernel
317 LEN: 7790938
318 OFF: 168
319
320 This tells us that the kernel starts at byte offset 168 (decimal) in image.fit
321 and extends for about 7MB. Try changing a byte at 0x2000 (say) and run
322 fit_check_sign again. You should see something like:
323
324 Verifying Hash Integrity ... sha1,rsa2048:dev+
325 ## Loading kernel from FIT Image at 7f5a39571000 ...
326    Using 'conf-1' configuration
327    Verifying Hash Integrity ...
328 sha1,rsa2048:dev+
329 OK
330
331    Trying 'kernel' kernel subimage
332      Description:  unavailable
333      Created:      Sun Jun  1 13:09:21 2014
334      Type:         Kernel Image
335      Compression:  lzo compressed
336      Data Size:    7790938 Bytes = 7608.34 kB = 7.43 MB
337      Architecture: ARM
338      OS:           Linux
339      Load Address: 0x80008000
340      Entry Point:  0x80008000
341      Hash algo:    sha1
342      Hash value:   c94364646427e10f423837e559898ef02c97b988
343    Verifying Hash Integrity ...
344 sha1 error
345 Bad hash value for 'hash-1' hash node in 'kernel' image node
346 Bad Data Hash
347
348 ## Loading fdt from FIT Image at 7f5a39571000 ...
349    Using 'conf-1' configuration
350    Trying 'fdt-1' fdt subimage
351      Description:  beaglebone-black
352      Created:      Sun Jun  1 13:09:21 2014
353      Type:         Flat Device Tree
354      Compression:  uncompressed
355      Data Size:    31547 Bytes = 30.81 kB = 0.03 MB
356      Architecture: ARM
357      Hash algo:    sha1
358      Hash value:   cb09202f889d824f23b8e4404b781be5ad38a68d
359    Verifying Hash Integrity ...
360 sha1+
361 OK
362
363    Loading Flat Device Tree ... OK
364
365 ## Loading ramdisk from FIT Image at 7f5a39571000 ...
366    Using 'conf-1' configuration
367 Could not find subimage node
368
369 Signature check Bad (error 1)
370
371
372 It has detected the change in the kernel.
373
374 You can also be sneaky and try to switch images, using the libfdt utilities
375 that come with dtc (package name is device-tree-compiler but you will need a
376 recent version like 1.4:
377
378    dtc -v
379 Version: DTC 1.4.0
380
381 First we can check which nodes are actually hashed by the configuration:
382
383    fdtget -l image.fit /
384 images
385 configurations
386
387    fdtget -l image.fit /configurations
388 conf-1
389 fdtget -l image.fit /configurations/conf-1
390 signature-1
391
392    fdtget -p image.fit /configurations/conf-1/signature-1
393 hashed-strings
394 hashed-nodes
395 timestamp
396 signer-version
397 signer-name
398 value
399 algo
400 key-name-hint
401 sign-images
402
403    fdtget image.fit /configurations/conf-1/signature-1 hashed-nodes
404 / /configurations/conf-1 /images/fdt-1 /images/fdt-1/hash /images/kernel /images/kernel/hash-1
405
406 This gives us a bit of a look into the signature that mkimage added. Note you
407 can also use fdtdump to list the entire device tree.
408
409 Say we want to change the kernel that this configuration uses
410 (/images/kernel). We could just put a new kernel in the image, but we will
411 need to change the hash to match. Let's simulate that by changing a byte of
412 the hash:
413
414     fdtget -tx image.fit /images/kernel/hash-1 value
415 c9436464 6427e10f 423837e5 59898ef0 2c97b988
416     fdtput -tx image.fit /images/kernel/hash-1 value c9436464 6427e10f 423837e5 59898ef0 2c97b981
417
418 Now check it again:
419
420    $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb
421 Verifying Hash Integrity ... sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13
422 rsa_verify_with_keynode: RSA failed to verify: -13
423 -
424 Failed to verify required signature 'key-dev'
425 Signature check Bad (error 1)
426
427 This time we don't even get as far as checking the images, since the
428 configuration signature doesn't match. We can't change any hashes without the
429 signature check noticing. The configuration is essentially locked. U-Boot has
430 a public key for which it requires a match, and will not permit the use of any
431 configuration that does not match that public key. The only way the
432 configuration will match is if it was signed by the matching private key.
433
434 It would also be possible to add a new signature node that does match your new
435 configuration. But that won't work since you are not allowed to change the
436 configuration in any way. Try it with a fresh (valid) image if you like by
437 running the mkimage link again. Then:
438
439    fdtput -p image.fit /configurations/conf-1/signature-1 value fred
440    $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb
441 Verifying Hash Integrity ... -
442 sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13
443 rsa_verify_with_keynode: RSA failed to verify: -13
444 -
445 Failed to verify required signature 'key-dev'
446 Signature check Bad (error 1)
447
448
449 Of course it would be possible to add an entirely new configuration and boot
450 with that, but it still needs to be signed, so it won't help.
451
452
453 6. Put the public key into U-Boot's image
454 -----------------------------------------
455
456 Having confirmed that the signature is doing its job, let's try it out in
457 U-Boot on the board. U-Boot needs access to the public key corresponding to
458 the private key that you signed with so that it can verify any kernels that
459 you sign.
460
461    cd $UBOOT
462    make O=b/am335x_boneblack_vboot EXT_DTB=${WORK}/am335x-boneblack-pubkey.dtb
463
464 Here we are overriding the normal device tree file with our one, which
465 contains the public key.
466
467 Now you have a special U-Boot image with the public key. It can verify can
468 kernel that you sign with the private key as in step 5.
469
470 If you like you can take a look at the public key information that mkimage
471 added to U-Boot's device tree:
472
473    fdtget -p am335x-boneblack-pubkey.dtb /signature/key-dev
474 required
475 algo
476 rsa,r-squared
477 rsa,modulus
478 rsa,n0-inverse
479 rsa,num-bits
480 key-name-hint
481
482 This has information about the key and some pre-processed values which U-Boot
483 can use to verify against it. These values are obtained from the public key
484 certificate by mkimage, but require quite a bit of code to generate. To save
485 code space in U-Boot, the information is extracted and written in raw form for
486 U-Boot to easily use. The same mechanism is used in Google's Chrome OS.
487
488 Notice the 'required' property. This marks the key as required - U-Boot will
489 not boot any image that does not verify against this key.
490
491
492 7. Put U-Boot and the kernel onto the board
493 -------------------------------------------
494
495 The method here varies depending on how you are booting. For this example we
496 are booting from an micro-SD card with two partitions, one for U-Boot and one
497 for Linux. Put it into your machine and write U-Boot and the kernel to it.
498 Here the card is /dev/sde:
499
500    cd $WORK
501    export UDEV=/dev/sde1   # Change thes two lines to the correct device
502    export KDEV=/dev/sde2
503    sudo mount $UDEV /mnt/tmp && sudo cp $UOUT/u-boot-dtb.img /mnt/tmp/u-boot.img  && sleep 1 && sudo umount $UDEV
504    sudo mount $KDEV /mnt/tmp && sudo cp $WORK/image.fit /mnt/tmp/boot/image.fit && sleep 1 && sudo umount $KDEV
505
506
507 8. Try it
508 ---------
509
510 Boot the board using the commands below:
511
512    setenv bootargs console=ttyO0,115200n8 quiet root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait
513    ext2load mmc 0:2 82000000 /boot/image.fit
514    bootm 82000000
515
516 You should then see something like this:
517
518 U-Boot# setenv bootargs console=ttyO0,115200n8 quiet root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait
519 U-Boot# ext2load mmc 0:2 82000000 /boot/image.fit
520 7824930 bytes read in 589 ms (12.7 MiB/s)
521 U-Boot# bootm 82000000
522 ## Loading kernel from FIT Image at 82000000 ...
523    Using 'conf-1' configuration
524    Verifying Hash Integrity ... sha1,rsa2048:dev+ OK
525    Trying 'kernel' kernel subimage
526      Description:  unavailable
527      Created:      2014-06-01  19:32:54 UTC
528      Type:         Kernel Image
529      Compression:  lzo compressed
530      Data Start:   0x820000a8
531      Data Size:    7790938 Bytes = 7.4 MiB
532      Architecture: ARM
533      OS:           Linux
534      Load Address: 0x80008000
535      Entry Point:  0x80008000
536      Hash algo:    sha1
537      Hash value:   c94364646427e10f423837e559898ef02c97b988
538    Verifying Hash Integrity ... sha1+ OK
539 ## Loading fdt from FIT Image at 82000000 ...
540    Using 'conf-1' configuration
541    Trying 'fdt-1' fdt subimage
542      Description:  beaglebone-black
543      Created:      2014-06-01  19:32:54 UTC
544      Type:         Flat Device Tree
545      Compression:  uncompressed
546      Data Start:   0x8276e2ec
547      Data Size:    31547 Bytes = 30.8 KiB
548      Architecture: ARM
549      Hash algo:    sha1
550      Hash value:   cb09202f889d824f23b8e4404b781be5ad38a68d
551    Verifying Hash Integrity ... sha1+ OK
552    Booting using the fdt blob at 0x8276e2ec
553    Uncompressing Kernel Image ... OK
554    Loading Device Tree to 8fff5000, end 8ffffb3a ... OK
555
556 Starting kernel ...
557
558 [    0.582377] omap_init_mbox: hwmod doesn't have valid attrs
559 [    2.589651] musb-hdrc musb-hdrc.0.auto: Failed to request rx1.
560 [    2.595830] musb-hdrc musb-hdrc.0.auto: musb_init_controller failed with status -517
561 [    2.606470] musb-hdrc musb-hdrc.1.auto: Failed to request rx1.
562 [    2.612723] musb-hdrc musb-hdrc.1.auto: musb_init_controller failed with status -517
563 [    2.940808] drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
564 [    7.248889] libphy: PHY 4a101000.mdio:01 not found
565 [    7.253995] net eth0: phy 4a101000.mdio:01 not found on slave 1
566 systemd-fsck[83]: Angstrom: clean, 50607/218160 files, 306348/872448 blocks
567
568 .---O---.
569 |       |                  .-.           o o
570 |   |   |-----.-----.-----.| |   .----..-----.-----.
571 |       |     | __  |  ---'| '--.|  .-'|     |     |
572 |   |   |  |  |     |---  ||  --'|  |  |  '  | | | |
573 '---'---'--'--'--.  |-----''----''--'  '-----'-'-'-'
574                 -'  |
575                 '---'
576
577 The Angstrom Distribution beaglebone ttyO0
578
579 Angstrom v2012.12 - Kernel 3.14.1+
580
581 beaglebone login:
582
583 At this point your kernel has been verified and you can be sure that it is one
584 that you signed. As an exercise, try changing image.fit as in step 5 and see
585 what happens.
586
587
588 Further Improvements
589 --------------------
590
591 Several of the steps here can be easily automated. In particular it would be
592 capital if signing and packaging a kernel were easy, perhaps a simple make
593 target in the kernel.
594
595 Some mention of how to use multiple .dtb files in a FIT might be useful.
596
597 U-Boot's verified boot mechanism has not had a robust and independent security
598 review. Such a review should look at the implementation and its resistance to
599 attacks.
600
601 Perhaps the verified boot feature could could be integrated into the Amstrom
602 distribution.
603
604
605 Simon Glass
606 sjg@chromium.org
607 2-June-14