1U-Boot FIT Signature Verification 2================================= 3 4Introduction 5------------ 6FIT supports hashing of images so that these hashes can be checked on 7loading. This protects against corruption of the image. However it does not 8prevent the substitution of one image for another. 9 10The signature feature allows the hash to be signed with a private key such 11that it can be verified using a public key later. Provided that the private 12key is kept secret and the public key is stored in a non-volatile place, 13any image can be verified in this way. 14 15See verified-boot.txt for more general information on verified boot. 16 17 18Concepts 19-------- 20Some familiarity with public key cryptography is assumed in this section. 21 22The procedure for signing is as follows: 23 24 - hash an image in the FIT 25 - sign the hash with a private key to produce a signature 26 - store the resulting signature in the FIT 27 28The procedure for verification is: 29 30 - read the FIT 31 - obtain the public key 32 - extract the signature from the FIT 33 - hash the image from the FIT 34 - verify (with the public key) that the extracted signature matches the 35 hash 36 37The signing is generally performed by mkimage, as part of making a firmware 38image for the device. The verification is normally done in U-Boot on the 39device. 40 41 42Algorithms 43---------- 44In principle any suitable algorithm can be used to sign and verify a hash. 45At present only one class of algorithms is supported: SHA1 hashing with RSA. 46This works by hashing the image to produce a 20-byte hash. 47 48While it is acceptable to bring in large cryptographic libraries such as 49openssl on the host side (e.g. mkimage), it is not desirable for U-Boot. 50For the run-time verification side, it is important to keep code and data 51size as small as possible. 52 53For this reason the RSA image verification uses pre-processed public keys 54which can be used with a very small amount of code - just some extraction 55of data from the FDT and exponentiation mod n. Code size impact is a little 56under 5KB on Tegra Seaboard, for example. 57 58It is relatively straightforward to add new algorithms if required. If 59another RSA variant is needed, then it can be added to the table in 60image-sig.c. If another algorithm is needed (such as DSA) then it can be 61placed alongside rsa.c, and its functions added to the table in image-sig.c 62also. 63 64 65Creating an RSA key and certificate 66----------------------------------- 67To create a new public key, size 2048 bits: 68 69$ openssl genrsa -F4 -out keys/dev.key 2048 70 71To create a certificate for this: 72 73$ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt 74 75If you like you can look at the public key also: 76 77$ openssl rsa -in keys/dev.key -pubout 78 79 80Device Tree Bindings 81-------------------- 82The following properties are required in the FIT's signature node(s) to 83allow thes signer to operate. These should be added to the .its file. 84Signature nodes sit at the same level as hash nodes and are called 85signature@1, signature@2, etc. 86 87- algo: Algorithm name (e.g. "sha1,rs2048") 88 89- key-name-hint: Name of key to use for signing. The keys will normally be in 90a single directory (parameter -k to mkimage). For a given key <name>, its 91private key is stored in <name>.key and the certificate is stored in 92<name>.crt. 93 94When the image is signed, the following properties are added (mandatory): 95 96- value: The signature data (e.g. 256 bytes for 2048-bit RSA) 97 98When the image is signed, the following properties are optional: 99 100- timestamp: Time when image was signed (standard Unix time_t format) 101 102- signer-name: Name of the signer (e.g. "mkimage") 103 104- signer-version: Version string of the signer (e.g. "2013.01") 105 106- comment: Additional information about the signer or image 107 108For config bindings (see Signed Configurations below), the following 109additional properties are optional: 110 111- sign-images: A list of images to sign, each being a property of the conf 112node that contains then. The default is "kernel,fdt" which means that these 113two images will be looked up in the config and signed if present. 114 115For config bindings, these properties are added by the signer: 116 117- hashed-nodes: A list of nodes which were hashed by the signer. Each is 118 a string - the full path to node. A typical value might be: 119 120 hashed-nodes = "/", "/configurations/conf@1", "/images/kernel@1", 121 "/images/kernel@1/hash@1", "/images/fdt@1", 122 "/images/fdt@1/hash@1"; 123 124- hashed-strings: The start and size of the string region of the FIT that 125 was hashed 126 127Example: See sign-images.its for an example image tree source file and 128sign-configs.its for config signing. 129 130 131Public Key Storage 132------------------ 133In order to verify an image that has been signed with a public key we need to 134have a trusted public key. This cannot be stored in the signed image, since 135it would be easy to alter. For this implementation we choose to store the 136public key in U-Boot's control FDT (using CONFIG_OF_CONTROL). 137 138Public keys should be stored as sub-nodes in a /signature node. Required 139properties are: 140 141- algo: Algorithm name (e.g. "sha1,rs2048") 142 143Optional properties are: 144 145- key-name-hint: Name of key used for signing. This is only a hint since it 146is possible for the name to be changed. Verification can proceed by checking 147all available signing keys until one matches. 148 149- required: If present this indicates that the key must be verified for the 150image / configuration to be considered valid. Only required keys are 151normally verified by the FIT image booting algorithm. Valid values are 152"image" to force verification of all images, and "conf" to force verfication 153of the selected configuration (which then relies on hashes in the images to 154verify those). 155 156Each signing algorithm has its own additional properties. 157 158For RSA the following are mandatory: 159 160- rsa,num-bits: Number of key bits (e.g. 2048) 161- rsa,modulus: Modulus (N) as a big-endian multi-word integer 162- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer 163- rsa,n0-inverse: -1 / modulus[0] mod 2^32 164 165 166Signed Configurations 167--------------------- 168While signing images is useful, it does not provide complete protection 169against several types of attack. For example, it it possible to create a 170FIT with the same signed images, but with the configuration changed such 171that a different one is selected (mix and match attack). It is also possible 172to substitute a signed image from an older FIT version into a newer FIT 173(roll-back attack). 174 175As an example, consider this FIT: 176 177/ { 178 images { 179 kernel@1 { 180 data = <data for kernel1> 181 signature@1 { 182 algo = "sha1,rsa2048"; 183 value = <...kernel signature 1...> 184 }; 185 }; 186 kernel@2 { 187 data = <data for kernel2> 188 signature@1 { 189 algo = "sha1,rsa2048"; 190 value = <...kernel signature 2...> 191 }; 192 }; 193 fdt@1 { 194 data = <data for fdt1>; 195 signature@1 { 196 algo = "sha1,rsa2048"; 197 vaue = <...fdt signature 1...> 198 }; 199 }; 200 fdt@2 { 201 data = <data for fdt2>; 202 signature@1 { 203 algo = "sha1,rsa2048"; 204 vaue = <...fdt signature 2...> 205 }; 206 }; 207 }; 208 configurations { 209 default = "conf@1"; 210 conf@1 { 211 kernel = "kernel@1"; 212 fdt = "fdt@1"; 213 }; 214 conf@1 { 215 kernel = "kernel@2"; 216 fdt = "fdt@2"; 217 }; 218 }; 219}; 220 221Since both kernels are signed it is easy for an attacker to add a new 222configuration 3 with kernel 1 and fdt 2: 223 224 configurations { 225 default = "conf@1"; 226 conf@1 { 227 kernel = "kernel@1"; 228 fdt = "fdt@1"; 229 }; 230 conf@1 { 231 kernel = "kernel@2"; 232 fdt = "fdt@2"; 233 }; 234 conf@3 { 235 kernel = "kernel@1"; 236 fdt = "fdt@2"; 237 }; 238 }; 239 240With signed images, nothing protects against this. Whether it gains an 241advantage for the attacker is debatable, but it is not secure. 242 243To solved this problem, we support signed configurations. In this case it 244is the configurations that are signed, not the image. Each image has its 245own hash, and we include the hash in the configuration signature. 246 247So the above example is adjusted to look like this: 248 249/ { 250 images { 251 kernel@1 { 252 data = <data for kernel1> 253 hash@1 { 254 algo = "sha1"; 255 value = <...kernel hash 1...> 256 }; 257 }; 258 kernel@2 { 259 data = <data for kernel2> 260 hash@1 { 261 algo = "sha1"; 262 value = <...kernel hash 2...> 263 }; 264 }; 265 fdt@1 { 266 data = <data for fdt1>; 267 hash@1 { 268 algo = "sha1"; 269 value = <...fdt hash 1...> 270 }; 271 }; 272 fdt@2 { 273 data = <data for fdt2>; 274 hash@1 { 275 algo = "sha1"; 276 value = <...fdt hash 2...> 277 }; 278 }; 279 }; 280 configurations { 281 default = "conf@1"; 282 conf@1 { 283 kernel = "kernel@1"; 284 fdt = "fdt@1"; 285 signature@1 { 286 algo = "sha1,rsa2048"; 287 value = <...conf 1 signature...>; 288 }; 289 }; 290 conf@2 { 291 kernel = "kernel@2"; 292 fdt = "fdt@2"; 293 signature@1 { 294 algo = "sha1,rsa2048"; 295 value = <...conf 1 signature...>; 296 }; 297 }; 298 }; 299}; 300 301 302You can see that we have added hashes for all images (since they are no 303longer signed), and a signature to each configuration. In the above example, 304mkimage will sign configurations/conf@1, the kernel and fdt that are 305pointed to by the configuration (/images/kernel@1, /images/kernel@1/hash@1, 306/images/fdt@1, /images/fdt@1/hash@1) and the root structure of the image 307(so that it isn't possible to add or remove root nodes). The signature is 308written into /configurations/conf@1/signature@1/value. It can easily be 309verified later even if the FIT has been signed with other keys in the 310meantime. 311 312 313Verification 314------------ 315FITs are verified when loaded. After the configuration is selected a list 316of required images is produced. If there are 'required' public keys, then 317each image must be verified against those keys. This means that every image 318that might be used by the target needs to be signed with 'required' keys. 319 320This happens automatically as part of a bootm command when FITs are used. 321 322 323Enabling FIT Verification 324------------------------- 325In addition to the options to enable FIT itself, the following CONFIGs must 326be enabled: 327 328CONFIG_FIT_SIGNATURE - enable signing and verfication in FITs 329CONFIG_RSA - enable RSA algorithm for signing 330 331 332Testing 333------- 334An easy way to test signing and verfication is to use the test script 335provided in test/vboot/vboot_test.sh. This uses sandbox (a special version 336of U-Boot which runs under Linux) to show the operation of a 'bootm' 337command loading and verifying images. 338 339A sample run is show below: 340 341$ make O=sandbox sandbox_config 342$ make O=sandbox 343$ O=sandbox ./test/vboot/vboot_test.sh 344Simple Verified Boot Test 345========================= 346 347Please see doc/uImage.FIT/verified-boot.txt for more information 348 349/home/hs/ids/u-boot/sandbox/tools/mkimage -D -I dts -O dtb -p 2000 350Build keys 351do sha1 test 352Build FIT with signed images 353Test Verified Boot Run: unsigned signatures:: OK 354Sign images 355Test Verified Boot Run: signed images: OK 356Build FIT with signed configuration 357Test Verified Boot Run: unsigned config: OK 358Sign images 359Test Verified Boot Run: signed config: OK 360check signed config on the host 361OK 362Test Verified Boot Run: signed config: OK 363Test Verified Boot Run: signed config with bad hash: OK 364do sha256 test 365Build FIT with signed images 366Test Verified Boot Run: unsigned signatures:: OK 367Sign images 368Test Verified Boot Run: signed images: OK 369Build FIT with signed configuration 370Test Verified Boot Run: unsigned config: OK 371Sign images 372Test Verified Boot Run: signed config: OK 373check signed config on the host 374OK 375Test Verified Boot Run: signed config: OK 376Test Verified Boot Run: signed config with bad hash: OK 377 378Test passed 379 380Future Work 381----------- 382- Roll-back protection using a TPM is done using the tpm command. This can 383be scripted, but we might consider a default way of doing this, built into 384bootm. 385 386 387Possible Future Work 388-------------------- 389- Add support for other RSA/SHA variants, such as rsa4096,sha512. 390- Other algorithms besides RSA 391- More sandbox tests for failure modes 392- Passwords for keys/certificates 393- Perhaps implement OAEP 394- Enhance bootm to permit scripted signature verification (so that a script 395can verify an image but not actually boot it) 396 397 398Simon Glass 399sjg@chromium.org 4001-1-13 401