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