• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Verified Boot Storage Applet for AVB 2.0
2
3  - Status: Draft as of April 6, 2017
4
5## Introduction
6
7The application and support libraries in this directory provide
8a mechanism for a device's bootloader, using [AVB](https://android.googlesource.com/platform/external/avb/),
9to store sensitive information.  For a bootloader, sensitive information
10includes whether the device is unlocked or locked, whether it is unlockable,
11and what the minimum version of the OS/kernel is allowed to be booted.  It
12may also store other sensitive flags.
13
14The verified boot storage applet provides a mechanism to store this
15data in a way that enforceѕ the expected policies even if the higher level
16operating system is compromised or operates in an unexpected fashion.
17
18
19## Design Overview
20
21The Verified Boot Storage Applet, VBSA, provides three purpose-built
22interfaces:
23
24  - Lock storage and policy enforcement
25  - Rollback index storage
26  - Applet state
27
28Each will be detailed below.
29
30### Locks
31
32There are four supported lock types:
33
34  - `LOCK_CARRIER`
35  - `LOCK_DEVICE`
36  - `LOCK_BOOT`
37  - `LOCK_OWNER`
38
39Each lock has a single byte of "lock" storage.  If that byte is 0x0, then it is
40unlocked, or cleared.  If it is non-zero, then the lock is locked.  Any
41non-zero value is valid and may be used by the bootloader if any additional
42internal flagging is necessary.
43
44In addition, a lock may have associated metadata which must be supplied during
45lock or unlock, or both.
46
47See `ese_boot_lock_*` in include/ese/app/boot.h for the specific interfaces.
48
49
50#### LOCK\_CARRIER
51
52The Carrier Lock implements a lock which can only be set when the device is not
53in production and can only be unlocked if provided a cryptographic signature.
54
55This lock is available for use to implement "sim locking" or "phone locking"
56such that the carrier can determine if the device is allowed to boot an
57unsigned or unknown system image.
58
59To provision this lock, device-specific data must be provided in an exact
60format.  An example of this can be found in
61`'ese-boot-tool.cpp':collect_device_data()`.  This data is then provided to
62the applet using `ese_boot_lock_xset()`.
63
64##### Metadata format for locking/provisioning
65
66The following system attributes must be collected in the given order:
67
68  - ro.product.brand
69  - ro.product.device
70  - ro.build.product
71  - ro.serialno
72  - [Modem ID: MEID or IMEI]
73  - ro.product.manufacturer
74  - ro.product.model
75
76The data is serialized as follows:
77
78    \[length||string\]\[...\]
79
80The length is a `uint8_t` and the value is appended as a stream of
81`uint8_t` values.
82
83This data is then prefixed with the desired non-zero lock value before
84being submitted to the applet.  If successful, the applet will have
85stored a SHA256 hash of the device data
86
87Note, `LOCK_CARRIER` can only be locked (non-zero lock value) when the
88applet is not in 'production' mode.
89
90##### Clearing/unlocking
91
92If `LOCK_CARRIER` is set to a non-zero value and the applet is in
93production mode, then clearing the lock value requires authorization.
94
95Authorization comes in the form of a `RSA_SHA256-PKCS#1` signature over
96the provisioned device data SHA256 hash and a supplied montonically
97increasing "nonce".
98
99The nonce value must be higher than the last seen nonce value and the
100signature must validate using public key internally stored in the
101applet (`CarrierLock.java:PK_MOD`).
102
103To perform a clear, `ese_boot_lock_xset()` must be called with lock
104data that begins with 0x0, to clear the lock, and then contains data of
105the following format:
106
107```
108    unlockToken = VERSION || NONCE || SIGNATURE
109
110    SIGNATURE = RSA_Sign(SHA256(deviceData))
111```
112
113  - The version is a little endian `uint64_t` (8 bytes).
114  - The nonce is a little endian `uint64_t` (8 bytes).
115  - The signature is a RSA 2048-bit with SHA-256 PKCS#1 v1.5 (256 bytes).
116
117On unlock, the device data hash is cleared.
118
119##### Testing
120
121It is possible to test the key with a valid signature but a fake
122internal nonce and fake internal device data using
123`ese_boot_carrier_lock_test()`.  When using this interface, it
124expects the same unlock token as in the prior but prefixes with the
125fake data:
126
127```
128    testVector = LAST_NONCE || DEVICE_DATA || unlockToken
129```
130
131  - The last nonce is the value the nonce is compared against (8 bytes).
132  - Device data is a replacement for the internally stored SHA-256
133    hash of the deviec data. (32 bytes).
134
135#### LOCK\_DEVICE
136
137The device lock is one of the setting used by the bootloader to
138determine if the boot lock can be changed.  It may only be set by the
139operating system and is meant to protect the device from being reflashed
140by someone that cannot unlock or access the OS.  This may also be used
141by an enterprise administrator to control lock policy for managed
142devices.
143
144As `LOCK_DEVICE` has not metadata, it can be set and retrieved using
145`ese_boot_lock_set()` and `ese_boot_lock_get()`.
146
147#### LOCK\_BOOT
148
149The boot lock is used by the bootloader to control whether it should
150only boot verified system software or not.  When the lock value
151is cleared (0x0), the bootloader will boot anything.  When the lock
152value is non-zero, it should only boot software that is signed by a key
153stored in the bootloader except if `LOCK_OWNER` is set.  Discussion of
154`LOCK_OWNER` will follow.
155
156`LOCK_BOOT` can only be toggled when in the bootloader/fastboot and if
157both `LOCK_CARRIER` and `LOCK_DEVICE` are cleared/unlocked.
158
159As with `LOCK_DEVICE`, `LOCK_BOOT` has no metadata so it does not need the
160extended accessors.
161
162#### LOCK\_OWNER
163
164The owner lock is used by the bootloader to support an alternative
165OS signing key provided by the device owner.  `LOCK_OWNER` can only be
166toggled if `LOCK_BOOT` is cleared. `LOCK_OWNER` does not require
167any metadata to unlock, but to lock, it requires a blob of up to 2048
168bytes be provided.  This is just secure storage for use by the
169bootloader.  `LOCK_OWNER` may be toggled in the bootloader or the
170operating system.  This allows an unlocked device (`LOCK_BOOT=0x0`) to
171install an owner key using fastboot or using software on the operating
172system itself.
173
174Before `LOCK_OWNER`'s key should be honored by the bootloader, `LOCK_BOOT`
175should be set (in the bootloader) to enforce use of the key and to keep
176malicious software in the operating system from changing it.
177
178(Note, that the owner key should not be treated as equivalent to the
179bootloader's internally stored key in that the device user should have a
180means of knowing if an owner key is in use, but the requirement for the
181device to be unlocked implies both physical access the `LOCK_DEVICE`
182being cleared.)
183
184
185### Rollback storage
186
187Verifying an operating system kernel and image is useful both for system
188reliability and for ensuring that the software has not been modified by
189a malicious party.  However, if the system software is updated,
190malicious software may attempt to "roll" a device back to an older
191version in order to take advantage of mistakes in the older, verified
192code.
193
194Rollback index values, or versions, may be stored securely by the bootloader
195to prevent these problems.  The Verified Boot Storage applet provides
196eight 64-bit slots for storing a value.  They may be read at any time,
197but they may only be written to when the device is in the bootloader (or
198fastboot).
199
200Rollback storage is written to using
201`ese_boot_rollback_index_write()` and read using
202`ese_boot_rollback_index_read()`.
203
204### Applet state
205
206The applet supports two operational states:
207
208  - production=true
209  - production=false
210
211On initial installation, production is false.  When the applet is not
212in production mode, it does not enforce a number of security boundaries,
213such as requiring bootloader or hlos mode for lock toggling or
214CarrierLock verification.  This allows the factory tools to run in any
215mode and properly configure a default lock state.
216
217To transition to "production", a call to `ese_boot_set_production(true)`
218is necessary.
219
220To check the state and collect debugging information, the call
221`ese_boot_get_state()` will return the current bootloader value,
222the production state, any errors codes from lock initialization, and the
223contents of lock storage.
224
225#### Example applet provisioning
226
227After the applet is installed, a flow as follows would prepare the
228applet for use:
229
230  - `ese_boot_session_init();`
231  - `ese_boot_session_open();`
232  - `ese_boot_session_lock_xset(LOCK_OWNER, {0, ...});`
233  - `ese_boot_session_lock_set(LOCK_BOOT, 0x1);`
234  - `ese_boot_session_lock_set(LOCK_DEVICE, 0x1);`
235  - [collect device data]
236  - `ese_boot_session_lock_set(LOCK_CARRIER, {1, deviceData});`
237  - `ese_boot_session_set_production(true);`
238  - `ese_boot_session_close();`
239
240### Additional details
241
242#### Bootloader mode
243
244Bootloader mode detection depends on hardware support to signal the
245applet that the application processor has been reset.  Additionally,
246there is a mechanism for the bootloader to indicate that is loading the
247main OS where it flips the value.  This signal provides the assurances
248around when storage is mutable or not during the time a device is
249powered on.
250
251#### Error results
252
253EseAppResult is an enum that all `ese_boot_*` functions return.  The
254enum only covers the lower 16-bits.  The upper 16-bits are reserved for
255passing applet and secure element OS status for debugging and analysis.
256When the lower 16-bits are `ESE_APP_RESULT_ERROR_APPLET`, then the
257upper bytes will be the applet code. That code can then be
258cross-referenced in the applet by function and code.  If the lower
259bytes are `ESE_APP_RESULT_ERROR_OS`, then the status code are the
260ISO7816 code from an uncaught exception or OS-level error.
261
262##### Cooldown
263
264`ESE_APP_RESULT_ERROR_COOLDOWN` indicates that the secure element needs to
265stay powered on for a period of time -- either at the end of use or before the
266requested command can be serviced.  As the behavior is implementation specific,
267the only effective option is to keep the secure element powered for the number of
268seconds specified by the response `uint32_t`.
269
270For chips that support it, like the one this applet is being tested on, the
271cooldown time can be requested with a special APDU to `ese_transceive()`:
272
273```
274    FFE10000
275```
276
277In response, a 6 byte response will contain a `uint32_t` and a successful status
278code (`90 00`).  The unsigned little-endian integer indicates how many seconds
279the chip needs to stay powered and unused to cooldown.  If this happens before
280the locks or rollback storage can be read, the bootloader will need to
281determine a safe delay or recovery path until boot can proceed securely.
282
283## Examples
284
285There are many ways to integrate this library and the associated applet.
286Below are some concrete examples to guide standard approach.
287
288### Configuration in factory
289
290- Install configure the secure element and install the applets
291(outside of the scope of this document).
292- Boot to an environment to run the ese-boot-tool.
293- Leave the inBootloader() signal asserted (recommended but not required).
294- Configure the desired lock states:
295  - `# ese-boot-tool lock set carrier 1 modem-imei-string`
296  - `# ese-boot-tool lock set device 1`
297  - `# ese-boot-tool lock set boot 1`
298  - `# ese-boot-tool lock set owner 0`
299- To move from factory mode to production mode call:
300  - `# ese-boot-tool production set true`
301
302### Configuration during repair
303
304- Boot to an environment to run the ese-boot-tool.
305- Leave inBootloader() signal asserted or implement the steps below in
306  the bootloader.
307- Transition out of production mode:
308  - `# ese-boot-tool production set false`
309- If a `LOCK_CARRIER` problem is being repaired, it is possible to reset the
310  internal nonce counter and all lock state with the command below.  A full
311  lock reset is not expected in most cases.
312  - `# ese-boot-tool lock reset`
313- Reconfigure the lock states:
314  - `# ese-boot-tool lock set carrier 1 modem-imei-string`
315  - `# ese-boot-tool lock set device 1`
316  - `# ese-boot-tool lock set boot 1`
317  - `# ese-boot-tool lock set owner 0`
318    (To clear data from the owner lock, set owner 1 must be called with
319     4096 00s.)
320- Then move back to production mode:
321  - `# ese-boot-tool production set true`
322
323### Use during boot
324
325Do not load any non-repair or non-factory OS without clearing the inBootloader
326signal as the applet may be transitioned out of production mode and/or the
327rollback state may be changed.
328
329#### Checking rollback values
330
331- Read and write rollback values as per libavb using the API
332  - `ese_boot_rollback_index_write()`
333  - `ese_boot_rollback_index_read()`
334- Prior to leaving the bootloader, clear the inBootloader signal.
335
336As rollback index values can only be written when inBootloader signal is set,
337it is critical to clear it when leaving the bootloader.
338
339#### Checking locks
340
341The pseudo-code and comments below should outline the basic algorithm, but it
342does not include integration into libavb or include use of rollback index
343value checking:
344
345```
346// Read LOCK_BOOT
347ese_boot_lock_get(session, kEseBootLockIdBoot, &lockBoot);
348
349if (lockBoot != 0x0) {  // Boot is LOCKED.
350    // Read the LOCK_OWNER
351    ese_boot_lock_xget(session, kEseBootLockIdOwner, &lockOwner);
352    if (lockOwner != 0x0) {  // Owner is LOCKED
353      // Get the lock owner value with metadata.
354      // This is done as a second stage to avoid wasted copying when it
355      // is not locked.
356      uint8_t ownerData[kEseBootOwnerKeyMax + 1];
357      ese_boot_lock_xget(session, kEseBootLockIdOwner, ownerData
358                         sizeof(ownerData), &ownerDataUsed);
359      // lockOwner == ownerData[0]
360      // Parse the stored metadata into a key as per your bootloader
361      // design.
362      SomeBootKey key;
363      parseDeviceOwnerKeyForBooting(ownerData + 1, ownerDataUsed, &key);
364      // Boot using the supplied owner key
365      // (E.g., as part of avb_validate_vbmeta_public_key())
366      setDeviceOwnerKeyForBooting(&key);
367      continueBootFlow();
368} else {  // Boot is UNLOCKED (0x0)
369    // Perform the boot flow.
370    setBootIsUnverified();
371    continueBootFlow();
372}
373```
374
375### In fastboot
376
377- `LOCK_BOOT` may be toggled by a fastboot command.  If the conditions of
378  unlock are not allowed by applet policy, it will fail.
379- `LOCK_OWNER`may be toggled and set a boot key from a fastboot command
380  or from an unlocked OS image.
381- If the verified boot design dictates that rollback indices are clear on
382  lock/unlock, this can be done by calling
383  - `ese_boot_rollback_index_write()` on each slot with the value of 0.
384
385Note, `LOCK_DEVICE` and `LOCK_CARRIER` should not need to be used by fastboot.
386
387For debugging and support, it may be desirable to connect the
388`ese_boot_get_state()` to allow fastboot to return the current value of
389production, inbootloader, and the lock metadata.
390
391