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