README.md 12.4 KB
Newer Older
Stefano Babic's avatar
Stefano Babic committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# OS Security

## Secure Boot

Secure boot ensures only authenticated software runs on the device and is achieved by verifying digital signatures of the software prior to executing the code. 
To achieve secure boot SoC support is required. NXP i.MX processors family has support for it, this feature is marketed as High Assurance Boot (HAB).

### Build a chain of Trust

A typical Linux based system has the following components:

* Bootloader

* Kernel, Device Tree

* Root Filesystem + User applications

* Application data

#### Bootloader Authentication

Bootloader Authentication is processor specific. However the mechanisms are the same :

* Creating a public/private key pair
* Signing the bootloader using vendor-specific code signing tools (CST Tool for NXP)
* Burning the public key (or hash of public key) onto One-Time programmable (OTP) fuse on the processor during Production

The processor Boot-ROM code on power-on loads the bootloader with the signature/certificates appended to it,
then authenticates the software by performing the following steps:

* Verify the public key used in the signature/certificate with the one stored in the OTP fuses
* Extract the hash of bootloader from the signature using the verified public key
* Compare the extracted hash with the computed hash of the bootloader. If it matches the boot process is continued if not it stops


![HAB Authentication](HAB1.png)


##### NXP Signing Tool (CST)

CST Tool can be downloaded from NXP Website at :
https://www.nxp.com/webapp/sps/download/license.jsp?colCode=IMX_CST_TOOL

44
45
46
47
For imx8mp
https://www.nxp.com/webapp/Download?colCode=IMX_CST_TOOL_NEW

which was ```cst-3.3.1.tgz``` when writting this document.
Stefano Babic's avatar
Stefano Babic committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

* Certificates/keys generation:

create a serial number file that OpenSSL wil use for the certificate serial number:

        $ cd cst-2.3.3/keys
        $ echo "12345678" > serial

create a key pass file that contains a passphrase to protect the HAB code signing private keys:

        $ cd cst-2.3.3/keys
        $ echo 'xm5hg86s$ps' >  key_pass.txt
        $ echo 'xm5hg86s$ps' >> key_pass.txt

create the signature keys/certificates for hab4:

        cst-2.3.3/keys$ ./hab4_pki_tree.sh

       ...
       Do you want to use an existing CA key (y/n)?: n
       Do you want to use Elliptic Curve Cryptography (y/n)?: n
       Enter key length in bits for PKI tree: 4096
       Enter PKI tree duration (years): 10
       How many Super Root Keys should be generated? 4
       Do you want the SRK certificates to have the CA flag set? (y/n)?: y

generate the fuse table and binary hash:

        $ cd cst-2.3.3/crts
        $ ../linux64/bin/srktool -h 4 -t SRK_1_2_3_4_table.bin -e SRK_1_2_3_4_fuse.bin -d sha256 -c \
        SRK1_sha256_4096_65537_v3_ca_crt.pem,./SRK2_sha256_4096_65537_v3_ca_crt.pem,./SRK3_sha256_4096_65537_v3_ca_crt.pem,./SRK4_sha256_4096_65537_v3_ca_crt.pem -f 1
        
        
81
82
###### IMX.6 based boards

Stefano Babic's avatar
Stefano Babic committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
The hashes table that must be burned into the device to validate the public keys, can be generated from the fuse table above using the script:

        #!/bin/bash
        #
        # For iMX6 there are 3 banks available
        #
        bank=3
        word=0
        if [ $# -ne 1 ]; then
                echo Usage: $0  /path/to/SRK_1_2_3_4_fuse.bin
                exit 1
        fi
        for ((i=0; i<8; i++))
        do
                offset=$((i * 4))
                printf "fuse prog -y $bank $word %s\n" `hexdump -s $offset -n 4  -e '/4 "0x"' -e '/4 "%X""\n"' ${1}`
                ((word++))
        done

 a call example :
 
        imx6-hab-cst-sign$ ./imx6-u-boot_fuse_commands.sh /path/to/SRK_1_2_3_4_fuse.bin
        fuse prog -y 3 0 0x85CB70D5
        fuse prog -y 3 1 0xE3064103
        fuse prog -y 3 2 0xF372C459
        fuse prog -y 3 3 0x94C7ECBD
        fuse prog -y 3 4 0x3A98FD08
        fuse prog -y 3 5 0xFBFC10C4
        fuse prog -y 3 6 0x3007BA2B
        fuse prog -y 3 7 0xDED88E4C 
        
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
###### IMX.8 based boards

get the values for the fuses with

	$ hexdump -e '/4 "0x"' -e '/4 "%X""\n"' < SRK_1_2_3_4_fuse.bin
	0x85CB70D5
	0xE3064103
	0xF372C459
	0x94C7ECBD
	0x3A98FD08
	0xFBFC10C4
	0x3007BA2B
	0xDED88E4C

which leads in the following U-Boot commands:

	=> fuse prog -y 6 0 0x85CB70D5
	=> fuse prog -y 6 1 0xE3064103
	=> fuse prog -y 6 2 0xF372C459
	=> fuse prog -y 6 3 0x94C7ECBD
	=> fuse prog -y 7 0 0x3A98FD08
	=> fuse prog -y 7 1 0xFBFC10C4
	=> fuse prog -y 7 2 0x3007BA2B
	=> fuse prog -y 7 3 0xDED88E4C

Once it's *absolutely* sure about what has been done so far and that it works, you can “close” the device.
Stefano Babic's avatar
Stefano Babic committed
140
141
142

This step is IRREVERSIBLE, better make sure there is no HAB Events in open mode configuration!!!!

143
144
imx.6 case:

Stefano Babic's avatar
Stefano Babic committed
145
146
        fuse prog 0 6 0x2

147
148
149
150
imx.8 case:

	=> fuse prog 1 3 0x02000000

Stefano Babic's avatar
Stefano Babic committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
* Signing Process:

The first stage of HAB is the authentication of U-Boot. CST tool is used to generate the CSF data, which includes public
key, certificate, and instruction of authentication process. The CSF data is attached to the original u-boot.img. The process is
called Signature.
The IVT should be modified to contain a pointer to the CSF data. The original u-boot.img image size is around 0x27000 to
0x28000. For convenience, we first extend its size to 0x2F000 (with fill 0x5A). Then concatenate it with the CSF data. The
combined image is again extended to a fixed length (0x31000), which is used as the IVT image size parameter.
The new memory layout is shown in the following image layout:

![HAB Layout](HAB2.png)


This process is fully automated in Yocto by using the class uboot-hab-sign.bbclass which is using the default settings:


       # HAB Settings
       HAB_ENABLE= "1"
       HAB_DIR ?= "${HAB_BASE}/conf/hab"
       SRKTAB ?= "${HAB_DIR}/crts/SRK_1_2_3_4_table.bin"
       CSFK ?= "${HAB_DIR}/crts/CSF1_1_sha256_4096_65537_v3_usr_crt.pem"
       SIGN_CERT ?= "${HAB_DIR}/crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem"

U-Boot is signed then with developement Certificates/keys, For production the local.conf can be used to overwrite those settings by the productive ones.

176
177
178
179
180
181
182
183
The outcome of the process is:

| Image  | imx6 | imx8 |
|--------|------|------|
| SPL    | SPL.signed | SPL.signed |
| U-Boot | u-boot-ivt.img-spi.signed | u-boot.itb.signed |

:warning: In imx8 case, you need to build U-Boot with SPL_FIT_GENERATOR disabled. See more infos [i.MX8M HAB](imx8_hab.md)
Stefano Babic's avatar
Stefano Babic committed
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

## Signed Filesystem

To extend the chain of Trust to the Applications, the Root Filesystem must be authenticated on each boot to check it's validity using Digital Signature Verification.
there are several way to achieve this goal such as dm-verity, dm-integrity, IMA/EVM,...But we chose a simple way to implement it by verifying the wohl Rootfs Partition Signature 
in Initramfs before mounting it:


        # +------------+  0x0                     -
        # |            |                          |
        # |            |                          |
        # |            |                          |
        # |            |                          |
        # | File       |                          |
        # | System     |                          |
        # .            |                          |
        # .            |                           > PAYLOAD to be signed      ----+
        # .            |                          |                                |
        # |            |                          |                                |
        # |            |                          |                                |
        # +------------+                          |                                |
        # |            |                          |                                |
        # | Fill Data  |                          |                                |
        # |            |                          |                                |
        # +------------+ MAGIC_OFFSET(MB Aligned) |                                |
        # | Magic      |                          |                                |
        # +------------+ MAGIC_OFFSET + MAGIC_LEN -                                |
        # |            |                                                           |
        # | Signature  | <---------------------------------------------------------+
        # |            |
        # +------------+


1) The rootfs image size is aligned to MB blocks

219
2) Magic Header is appended to those blocks
Stefano Babic's avatar
Stefano Babic committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

3) The sum is then hashed signed and signature is the appended


The class *sign-fs.bbclass*

is automatically performing this process and is using the default settings:


        CA_CERT ?= "${HAB_DIR}/crts/CA1_sha256_4096_65537_v3_ca_crt.pem"
        ROOT_CERT ?= "${HAB_DIR}/crts/SRK1_sha256_4096_65537_v3_ca_crt.pem"
        SIGN_KEY ?= "${HAB_DIR}/keys/IMG1_1_sha256_4096_65537_v3_usr_key.pem"
        PASS_FILE ?= "${HAB_DIR}/keys/key_pass.txt"

added to machine conf or local conf will generate the signed rootfs in deploy folder:

        IMAGE_FSTYPES = "squashfs.signed"

On boot the initramfs is performing the reverse process to verify the digital signature of the rootfs:


        # +------------+  0x0 (MMC_PART_START) ----
        # |            |                          |
        # |            |                          |
        # |            |                          |
        # |            |                          |
        # | File       |                          |
        # | System     |                          |
        # .            |                          |
        # .            |                           > PAYLOAD to be verified    ----+
        # .            |                          |                                |
        # |            |                          |                                |
        # |            |                          |                                |
        # +------------+                          |                                |
        # |            |                          |                                |
        # | Fill Data  |                          |                                |
        # |            |                          |                                |
        # +------------+ MAGIC_OFFSET(MB Aligned) |                                |
        # | Magic      |                          |                                |
        # +------------+ MAGIC_OFFSET + MAGIC_LEN -                                |
        # |            |                                                           |
        # | Signature  | <---------------------------------------------------------+
        # |            |
        # +------------+


### encrypted rootfs (read only squashfs)

As rootfs we use a read-only squashfs (ramdisk). The rootfs is crypted
with dm-crypt with AES-128-GCM.

The class *crypt-fs.bbclass*
performs the needed steps to crypt the FS image.

As it is not a good idea to store the key in plain, we use the
DCP or CAAM for crypting the raw key and get a key blob we can store
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
in the SPI NOR.

The blob is stored on a project specific device. The user of the layer
should provide a /etc/default/initramfs file, that loads the blob
and copies it into /tmp/key.blob. This is used by the ramdisk to setup
the encryptded rootfs.

To create and store the blob:

	keyctl add symmetric "rootfskey" "<engine> load_plain <key hex text>" @s

For example:

	keyctl add symmetric "rootfskey" "caam load_plain 0102030405060708AABBCCDDEEFF12AA" @s
	keyctl show -x

You get an id for the key.

Then export the blob:

	keyctl pipe <key id> > /tmp/blob

And copy the resulting blob on a persistent device. The real key is never exposed and it is
decrypted with the unique key of the device, so this procedure must be done for each produced
device in the factory.
Stefano Babic's avatar
Stefano Babic committed
301

302
303
304
305
306
307
308
309
#### raw key definitions

define for example your raw key for the rootfs image:

ENC_KEY_RAW ?= "fdf6842566d47e47d6874da561fec433"

so the ```crypt-fs``` can use it. This key *never* should be lost!

Stefano Babic's avatar
Stefano Babic committed
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
### DCP usage

see implementation details in *dcp_overview.pdf*

### order of execution

We first crypt the FS image, than sign it, so on boot we first
check the signature and if the signature is OK, we encrypt the
FS image.

See the initrd script: *recipes-core/initrdscripts/files/initramfs-init.sh*

### setup

Intentionally using this meta layer as it is will fail your build.

You must add the keys for HAB boot, signed FS somehow to your yocto build
setup.

This can be done by simply adding another meta layer, which contains all the needed
keys.

Add this meta layer to your build and you use the default keys from there.

Of course, do not use them in your product!