1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (c) 2019, Linaro Limited 3# Author: AKASHI Takahiro <takahiro.akashi@linaro.org> 4# 5# U-Boot UEFI: Signed Image Authentication Test 6 7""" 8This test verifies image authentication for signed images. 9""" 10 11import pytest 12 13 14@pytest.mark.boardspec('sandbox') 15@pytest.mark.buildconfigspec('efi_secure_boot') 16@pytest.mark.buildconfigspec('cmd_efidebug') 17@pytest.mark.buildconfigspec('cmd_fat') 18@pytest.mark.buildconfigspec('cmd_nvedit_efi') 19@pytest.mark.slow 20class TestEfiSignedImage(object): 21 def test_efi_signed_image_auth1(self, u_boot_console, efi_boot_env): 22 """ 23 Test Case 1 - Secure boot is not in force 24 """ 25 u_boot_console.restart_uboot() 26 disk_img = efi_boot_env 27 with u_boot_console.log.section('Test Case 1a'): 28 # Test Case 1a, run signed image if no PK 29 output = u_boot_console.run_command_list([ 30 'host bind 0 %s' % disk_img, 31 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed -s ""', 32 'efidebug boot order 1', 33 'bootefi bootmgr']) 34 assert 'Hello, world!' in ''.join(output) 35 36 with u_boot_console.log.section('Test Case 1b'): 37 # Test Case 1b, run unsigned image if no PK 38 output = u_boot_console.run_command_list([ 39 'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi -s ""', 40 'efidebug boot order 2', 41 'bootefi bootmgr']) 42 assert 'Hello, world!' in ''.join(output) 43 44 def test_efi_signed_image_auth2(self, u_boot_console, efi_boot_env): 45 """ 46 Test Case 2 - Secure boot is in force, 47 authenticated by db (TEST_db certificate in db) 48 """ 49 u_boot_console.restart_uboot() 50 disk_img = efi_boot_env 51 with u_boot_console.log.section('Test Case 2a'): 52 # Test Case 2a, db is not yet installed 53 output = u_boot_console.run_command_list([ 54 'host bind 0 %s' % disk_img, 55 'fatload host 0:1 4000000 KEK.auth', 56 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 57 'fatload host 0:1 4000000 PK.auth', 58 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 59 assert 'Failed to set EFI variable' not in ''.join(output) 60 output = u_boot_console.run_command_list([ 61 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed -s ""', 62 'efidebug boot order 1', 63 'efidebug test bootmgr']) 64 assert('\'HELLO1\' failed' in ''.join(output)) 65 assert('efi_bootmgr_load() returned: 26' in ''.join(output)) 66 output = u_boot_console.run_command_list([ 67 'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi -s ""', 68 'efidebug boot order 2', 69 'efidebug test bootmgr']) 70 assert '\'HELLO2\' failed' in ''.join(output) 71 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 72 73 with u_boot_console.log.section('Test Case 2b'): 74 # Test Case 2b, authenticated by db 75 output = u_boot_console.run_command_list([ 76 'fatload host 0:1 4000000 db.auth', 77 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db']) 78 assert 'Failed to set EFI variable' not in ''.join(output) 79 output = u_boot_console.run_command_list([ 80 'efidebug boot order 2', 81 'efidebug test bootmgr']) 82 assert '\'HELLO2\' failed' in ''.join(output) 83 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 84 output = u_boot_console.run_command_list([ 85 'efidebug boot order 1', 86 'bootefi bootmgr']) 87 assert 'Hello, world!' in ''.join(output) 88 89 def test_efi_signed_image_auth3(self, u_boot_console, efi_boot_env): 90 """ 91 Test Case 3 - rejected by dbx (TEST_db certificate in dbx) 92 """ 93 u_boot_console.restart_uboot() 94 disk_img = efi_boot_env 95 with u_boot_console.log.section('Test Case 3a'): 96 # Test Case 3a, rejected by dbx 97 output = u_boot_console.run_command_list([ 98 'host bind 0 %s' % disk_img, 99 'fatload host 0:1 4000000 db.auth', 100 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx', 101 'fatload host 0:1 4000000 KEK.auth', 102 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 103 'fatload host 0:1 4000000 PK.auth', 104 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 105 assert 'Failed to set EFI variable' not in ''.join(output) 106 output = u_boot_console.run_command_list([ 107 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', 108 'efidebug boot order 1', 109 'efidebug test bootmgr']) 110 assert '\'HELLO\' failed' in ''.join(output) 111 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 112 113 with u_boot_console.log.section('Test Case 3b'): 114 # Test Case 3b, rejected by dbx even if db allows 115 output = u_boot_console.run_command_list([ 116 'fatload host 0:1 4000000 db.auth', 117 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db']) 118 assert 'Failed to set EFI variable' not in ''.join(output) 119 output = u_boot_console.run_command_list([ 120 'efidebug boot order 1', 121 'efidebug test bootmgr']) 122 assert '\'HELLO\' failed' in ''.join(output) 123 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 124 125 def test_efi_signed_image_auth4(self, u_boot_console, efi_boot_env): 126 """ 127 Test Case 4 - revoked by dbx (digest of TEST_db certificate in dbx) 128 """ 129 u_boot_console.restart_uboot() 130 disk_img = efi_boot_env 131 with u_boot_console.log.section('Test Case 4'): 132 # Test Case 4, rejected by dbx 133 output = u_boot_console.run_command_list([ 134 'host bind 0 %s' % disk_img, 135 'fatload host 0:1 4000000 dbx_hash.auth', 136 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx', 137 'fatload host 0:1 4000000 db.auth', 138 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 139 'fatload host 0:1 4000000 KEK.auth', 140 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 141 'fatload host 0:1 4000000 PK.auth', 142 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 143 assert 'Failed to set EFI variable' not in ''.join(output) 144 output = u_boot_console.run_command_list([ 145 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', 146 'efidebug boot order 1', 147 'efidebug test bootmgr']) 148 assert '\'HELLO\' failed' in ''.join(output) 149 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 150 151 def test_efi_signed_image_auth5(self, u_boot_console, efi_boot_env): 152 """ 153 Test Case 5 - multiple signatures 154 one signed with TEST_db, and 155 one signed with TEST_db1 156 """ 157 u_boot_console.restart_uboot() 158 disk_img = efi_boot_env 159 with u_boot_console.log.section('Test Case 5a'): 160 # Test Case 5a, authenticated even if only one of signatures 161 # is verified 162 output = u_boot_console.run_command_list([ 163 'host bind 0 %s' % disk_img, 164 'fatload host 0:1 4000000 db.auth', 165 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 166 'fatload host 0:1 4000000 KEK.auth', 167 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 168 'fatload host 0:1 4000000 PK.auth', 169 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 170 assert 'Failed to set EFI variable' not in ''.join(output) 171 output = u_boot_console.run_command_list([ 172 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', 173 'efidebug boot order 1', 174 'efidebug test bootmgr']) 175 assert 'Hello, world!' in ''.join(output) 176 177 with u_boot_console.log.section('Test Case 5b'): 178 # Test Case 5b, authenticated if both signatures are verified 179 output = u_boot_console.run_command_list([ 180 'fatload host 0:1 4000000 db2.auth', 181 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db']) 182 assert 'Failed to set EFI variable' not in ''.join(output) 183 output = u_boot_console.run_command_list([ 184 'efidebug boot order 1', 185 'efidebug test bootmgr']) 186 assert 'Hello, world!' in ''.join(output) 187 188 with u_boot_console.log.section('Test Case 5c'): 189 # Test Case 5c, rejected if one of signatures (digest of 190 # certificate) is revoked 191 output = u_boot_console.run_command_list([ 192 'fatload host 0:1 4000000 dbx_hash.auth', 193 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 194 assert 'Failed to set EFI variable' not in ''.join(output) 195 output = u_boot_console.run_command_list([ 196 'efidebug boot order 1', 197 'efidebug test bootmgr']) 198 assert '\'HELLO\' failed' in ''.join(output) 199 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 200 201 with u_boot_console.log.section('Test Case 5d'): 202 # Test Case 5d, rejected if both of signatures are revoked 203 output = u_boot_console.run_command_list([ 204 'fatload host 0:1 4000000 dbx_hash2.auth', 205 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize dbx']) 206 assert 'Failed to set EFI variable' not in ''.join(output) 207 output = u_boot_console.run_command_list([ 208 'efidebug boot order 1', 209 'efidebug test bootmgr']) 210 assert '\'HELLO\' failed' in ''.join(output) 211 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 212 213 # Try rejection in reverse order. 214 u_boot_console.restart_uboot() 215 with u_boot_console.log.section('Test Case 5e'): 216 # Test Case 5e, authenticated even if only one of signatures 217 # is verified. Same as before but reject dbx_hash1.auth only 218 output = u_boot_console.run_command_list([ 219 'host bind 0 %s' % disk_img, 220 'fatload host 0:1 4000000 db.auth', 221 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 222 'fatload host 0:1 4000000 KEK.auth', 223 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 224 'fatload host 0:1 4000000 PK.auth', 225 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', 226 'fatload host 0:1 4000000 db2.auth', 227 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 228 'fatload host 0:1 4000000 dbx_hash1.auth', 229 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 230 assert 'Failed to set EFI variable' not in ''.join(output) 231 output = u_boot_console.run_command_list([ 232 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', 233 'efidebug boot order 1', 234 'efidebug test bootmgr']) 235 assert '\'HELLO\' failed' in ''.join(output) 236 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 237 238 def test_efi_signed_image_auth6(self, u_boot_console, efi_boot_env): 239 """ 240 Test Case 6 - using digest of signed image in database 241 """ 242 u_boot_console.restart_uboot() 243 disk_img = efi_boot_env 244 with u_boot_console.log.section('Test Case 6a'): 245 # Test Case 6a, verified by image's digest in db 246 output = u_boot_console.run_command_list([ 247 'host bind 0 %s' % disk_img, 248 'fatload host 0:1 4000000 db_hello_signed.auth', 249 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 250 'fatload host 0:1 4000000 KEK.auth', 251 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 252 'fatload host 0:1 4000000 PK.auth', 253 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 254 assert 'Failed to set EFI variable' not in ''.join(output) 255 output = u_boot_console.run_command_list([ 256 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', 257 'efidebug boot order 1', 258 'bootefi bootmgr']) 259 assert 'Hello, world!' in ''.join(output) 260 261 with u_boot_console.log.section('Test Case 6b'): 262 # Test Case 6b, rejected by TEST_db certificate in dbx 263 output = u_boot_console.run_command_list([ 264 'fatload host 0:1 4000000 dbx_db.auth', 265 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 266 assert 'Failed to set EFI variable' not in ''.join(output) 267 output = u_boot_console.run_command_list([ 268 'efidebug boot order 1', 269 'efidebug test bootmgr']) 270 assert '\'HELLO\' failed' in ''.join(output) 271 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 272 273 with u_boot_console.log.section('Test Case 6c'): 274 # Test Case 6c, rejected by image's digest in dbx 275 output = u_boot_console.run_command_list([ 276 'fatload host 0:1 4000000 db.auth', 277 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 278 'fatload host 0:1 4000000 dbx_hello_signed.auth', 279 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 280 assert 'Failed to set EFI variable' not in ''.join(output) 281 output = u_boot_console.run_command_list([ 282 'efidebug boot order 1', 283 'efidebug test bootmgr']) 284 assert '\'HELLO\' failed' in ''.join(output) 285 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 286 287 def test_efi_signed_image_auth7(self, u_boot_console, efi_boot_env): 288 """ 289 Test Case 7 - Reject images based on the sha384/512 of their x509 cert 290 """ 291 # sha384 of an x509 cert in dbx 292 u_boot_console.restart_uboot() 293 disk_img = efi_boot_env 294 with u_boot_console.log.section('Test Case 7a'): 295 output = u_boot_console.run_command_list([ 296 'host bind 0 %s' % disk_img, 297 'fatload host 0:1 4000000 db.auth', 298 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 299 'fatload host 0:1 4000000 KEK.auth', 300 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 301 'fatload host 0:1 4000000 PK.auth', 302 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', 303 'fatload host 0:1 4000000 db2.auth', 304 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 305 'fatload host 0:1 4000000 dbx_hash384.auth', 306 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 307 assert 'Failed to set EFI variable' not in ''.join(output) 308 output = u_boot_console.run_command_list([ 309 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', 310 'efidebug boot order 1', 311 'efidebug test bootmgr']) 312 assert '\'HELLO\' failed' in ''.join(output) 313 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 314 315 # sha512 of an x509 cert in dbx 316 u_boot_console.restart_uboot() 317 with u_boot_console.log.section('Test Case 7b'): 318 output = u_boot_console.run_command_list([ 319 'host bind 0 %s' % disk_img, 320 'fatload host 0:1 4000000 db.auth', 321 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 322 'fatload host 0:1 4000000 KEK.auth', 323 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 324 'fatload host 0:1 4000000 PK.auth', 325 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK', 326 'fatload host 0:1 4000000 db2.auth', 327 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db', 328 'fatload host 0:1 4000000 dbx_hash512.auth', 329 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) 330 assert 'Failed to set EFI variable' not in ''.join(output) 331 output = u_boot_console.run_command_list([ 332 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', 333 'efidebug boot order 1', 334 'efidebug test bootmgr']) 335 assert '\'HELLO\' failed' in ''.join(output) 336 assert 'efi_bootmgr_load() returned: 26' in ''.join(output) 337 338 def test_efi_signed_image_auth8(self, u_boot_console, efi_boot_env): 339 """ 340 Test Case 8 - Secure boot is in force, 341 Same as Test Case 2 but the image binary to be loaded 342 was willfully modified (forged) 343 Must be rejected. 344 """ 345 u_boot_console.restart_uboot() 346 disk_img = efi_boot_env 347 with u_boot_console.log.section('Test Case 8a'): 348 # Test Case 8a, Secure boot is not yet forced 349 output = u_boot_console.run_command_list([ 350 'host bind 0 %s' % disk_img, 351 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld_forged.efi.signed -s ""', 352 'efidebug boot order 1', 353 'efidebug test bootmgr']) 354 assert('hELLO, world!' in ''.join(output)) 355 356 with u_boot_console.log.section('Test Case 8b'): 357 # Test Case 8b, Install signature database and verify the image 358 output = u_boot_console.run_command_list([ 359 'fatload host 0:1 4000000 db.auth', 360 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', 361 'fatload host 0:1 4000000 KEK.auth', 362 'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK', 363 'fatload host 0:1 4000000 PK.auth', 364 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) 365 assert 'Failed to set EFI variable' not in ''.join(output) 366 output = u_boot_console.run_command_list([ 367 'efidebug boot order 1', 368 'efidebug test bootmgr']) 369 assert(not 'hELLO, world!' in ''.join(output)) 370 assert('\'HELLO1\' failed' in ''.join(output)) 371 assert('efi_bootmgr_load() returned: 26' in ''.join(output)) 372