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 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
32                'efidebug boot next 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 2 HELLO2 host 0:1 /helloworld.efi ""',
40                'efidebug boot next 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 1 HELLO1 host 0:1 /helloworld.efi.signed ""',
62                'efidebug boot next 1',
63                'efidebug test bootmgr'])
64            assert('\'HELLO1\' failed' in ''.join(output))
65            assert('efi_start_image() returned: 26' in ''.join(output))
66            output = u_boot_console.run_command_list([
67                'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""',
68                'efidebug boot next 2',
69                'efidebug test bootmgr'])
70            assert '\'HELLO2\' failed' in ''.join(output)
71            assert 'efi_start_image() 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 next 2',
81                'efidebug test bootmgr'])
82            assert '\'HELLO2\' failed' in ''.join(output)
83            assert 'efi_start_image() returned: 26' in ''.join(output)
84            output = u_boot_console.run_command_list([
85                'efidebug boot next 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 1 HELLO host 0:1 /helloworld.efi.signed ""',
108                'efidebug boot next 1',
109                'efidebug test bootmgr'])
110            assert '\'HELLO\' failed' in ''.join(output)
111            assert 'efi_start_image() 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 next 1',
121                'efidebug test bootmgr'])
122            assert '\'HELLO\' failed' in ''.join(output)
123            assert 'efi_start_image() 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 1 HELLO host 0:1 /helloworld.efi.signed ""',
146                'efidebug boot next 1',
147                'efidebug test bootmgr'])
148            assert '\'HELLO\' failed' in ''.join(output)
149            assert 'efi_start_image() 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 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""',
173                'efidebug boot next 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 db1.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 next 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, not 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 next 1',
197                'efidebug test bootmgr'])
198            assert 'Hello, world!' in ''.join(output)
199
200        with u_boot_console.log.section('Test Case 5d'):
201            # Test Case 5d, rejected if both of signatures are revoked
202            output = u_boot_console.run_command_list([
203                'fatload host 0:1 4000000 dbx_hash1.auth',
204                'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize dbx'])
205            assert 'Failed to set EFI variable' not in ''.join(output)
206            output = u_boot_console.run_command_list([
207                'efidebug boot next 1',
208                'efidebug test bootmgr'])
209            assert '\'HELLO\' failed' in ''.join(output)
210            assert 'efi_start_image() returned: 26' in ''.join(output)
211
212    def test_efi_signed_image_auth6(self, u_boot_console, efi_boot_env):
213        """
214        Test Case 6 - using digest of signed image in database
215        """
216        u_boot_console.restart_uboot()
217        disk_img = efi_boot_env
218        with u_boot_console.log.section('Test Case 6a'):
219            # Test Case 6a, verified by image's digest in db
220            output = u_boot_console.run_command_list([
221                'host bind 0 %s' % disk_img,
222                'fatload host 0:1 4000000 db_hello_signed.auth',
223                'setenv -e -nv -bs -rt -at -i 4000000:$filesize db',
224                'fatload host 0:1 4000000 KEK.auth',
225                'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK',
226                'fatload host 0:1 4000000 PK.auth',
227                'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK'])
228            assert 'Failed to set EFI variable' not in ''.join(output)
229            output = u_boot_console.run_command_list([
230                'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""',
231                'efidebug boot next 1',
232                'bootefi bootmgr'])
233            assert 'Hello, world!' in ''.join(output)
234
235        with u_boot_console.log.section('Test Case 6b'):
236            # Test Case 6b, rejected by TEST_db certificate in dbx
237            output = u_boot_console.run_command_list([
238                'fatload host 0:1 4000000 dbx_db.auth',
239                'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx'])
240            assert 'Failed to set EFI variable' not in ''.join(output)
241            output = u_boot_console.run_command_list([
242                'efidebug boot next 1',
243                'efidebug test bootmgr'])
244            assert '\'HELLO\' failed' in ''.join(output)
245            assert 'efi_start_image() returned: 26' in ''.join(output)
246
247        with u_boot_console.log.section('Test Case 6c'):
248            # Test Case 6c, rejected by image's digest in dbx
249            output = u_boot_console.run_command_list([
250                'fatload host 0:1 4000000 db.auth',
251                'setenv -e -nv -bs -rt -at -i 4000000:$filesize db',
252                'fatload host 0:1 4000000 dbx_hello_signed.auth',
253                'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx'])
254            assert 'Failed to set EFI variable' not in ''.join(output)
255            output = u_boot_console.run_command_list([
256                'efidebug boot next 1',
257                'efidebug test bootmgr'])
258            assert '\'HELLO\' failed' in ''.join(output)
259            assert 'efi_start_image() returned: 26' in ''.join(output)
260