Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 1 | Block Storage Service |
| 2 | ===================== |
| 3 | Overview |
| 4 | -------- |
| 5 | The Block Storage service can be used to share a block-oriented storage device |
| 6 | such as a QSPI flash between a set of independent secure world clients. A block |
| 7 | storage service provider presents a block level interface for accessing an |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 8 | underlying block storage device. The basic storage functionality provided by a |
| 9 | device can be extended by Stacked Block Stores, which add extra features, like |
| 10 | encryption or partitioning on top of a device. |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 11 | |
| 12 | The following diagram illustrates a firmware integration that uses a single block |
| 13 | storage service provider to control access to a dedicated flash device. In this |
| 14 | example StMM, OP-TEE, Update Agent and the Protected Storage SP act as clients of |
| 15 | the service. Each client independently manages its own filesystem and is presented |
| 16 | with its own logical partition, starting with a logical block address (LBA) of zero. |
| 17 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 18 | .. image:: ../image/block-storage-example-usage.svg |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 19 | |
| 20 | Project Directories |
| 21 | ------------------- |
| 22 | Components within the Trusted Services project related to the Block Storage service |
| 23 | are located under the following directories: |
| 24 | |
| 25 | .. list-table:: |
| 26 | :header-rows: 1 |
| 27 | |
| 28 | * - Directory |
| 29 | - Contains |
| 30 | * - ``components/service/block_storage`` |
| 31 | - Service specific code components. |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 32 | * - ``components/service/block_storage/block_store`` |
| 33 | - Client, devices, stacked block stores. |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 34 | * - ``deployments/block-storage`` |
| 35 | - Build files and deployment specific code for building alternative configurations |
| 36 | of the block storage service provider. |
| 37 | * - ``protocols/service/block_storage`` |
| 38 | - Service access protocol definitions. |
| 39 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 40 | Design Description |
| 41 | ------------------ |
| 42 | The block storage service provider conforms to the same model as other service providers |
| 43 | within the TS project. Service requests from clients are received by a service provider |
| 44 | that is responsible for parameter deserialization/serialization and service level access |
| 45 | control. Block storage operations are delegated to a backend *block_store* that provides |
| 46 | block-level storage in some way. There is much flexibility to realize the backend block-level |
| 47 | storage in different ways, allowing platform integrators to use alternative *block_store* |
| 48 | realizations to provide storage solutions that meet specific product requirements. |
| 49 | |
| 50 | The following class diagram illustrates the block storage service provider model: |
| 51 | |
| 52 | .. uml:: ../uml/BlockStorageProvider.puml |
| 53 | |
| 54 | Block Store |
| 55 | ^^^^^^^^^^^ |
| 56 | The *block_store* component defines a virtual interface for block IO operations. Alternative |
| 57 | concrete *block_store* implementations are supported. Some *block_store* components are stackable |
| 58 | over other *block_store* components to add features such as store partitioning or block |
| 59 | authentication. Separation of functionality into stackable *block_store* components gives |
| 60 | platform integrators the flexibility to create alternative storage solutions with different |
| 61 | security/cost tradeoffs. The base *block_store* interface is defined in:: |
| 62 | |
| 63 | components/service/block_storage/block_store/block_store.h |
| 64 | |
| 65 | Components that implement the *block_store* interface are located in subdirectories beneath |
| 66 | ``components/service/block_storage/block_store``. A *block_device* is class of *block_store* |
| 67 | that actually provides block-level storage. In a stack of *block_store* components, a |
| 68 | *block_device* will always live at the bottom. The following layer diagram illustrates a |
| 69 | typical block storage deployment where storage is provided by a stack of *block_store* components: |
| 70 | |
| 71 | .. image:: ../image/block-storage-layers.svg |
| 72 | |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 73 | Service Interface |
| 74 | ----------------- |
| 75 | The Block Storage service supports a conventional set of block-level operations that |
| 76 | can be adapted to different driver models by clients. The following table summarizes |
| 77 | supported operations: |
| 78 | |
| 79 | .. list-table:: |
| 80 | :header-rows: 1 |
| 81 | |
| 82 | * - Operation |
| 83 | - Description |
| 84 | * - Open |
| 85 | - Open a session - take the required *UniquePartitionGUID* as a parameter. Returns |
| 86 | a handle to be used as a qualifier for other requests made by a client. |
| 87 | * - Close |
| 88 | - Close a previously opened session. |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 89 | * - GetPartitionInfo |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 90 | - Returns information about the partition associated with an open session. Includes |
| 91 | the block size and the total number of blocks assigned to the partition. |
| 92 | * - Read |
| 93 | - Read data from the specified block. |
| 94 | * - Write |
| 95 | - Write data to the specified block. |
| 96 | * - Erase |
| 97 | - Erase a set of one or more blocks. |
| 98 | |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 99 | The service interface is realized by the block storage service provider. It delegates |
| 100 | storage operations to a backend *block_store*. The *block_store* defines a common |
| 101 | interface for components that realize block storage operations. Where an underlying storage |
| 102 | technology does not support an explicit erase operation (e.g. RPMB), the corresponding |
| 103 | concrete *block_store* should return success for a call to erase but perform no actual |
| 104 | operation (if the partition is writable and the LBA falls within the limits of the |
| 105 | partition). |
| 106 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 107 | Block Store Client |
| 108 | ------------------ |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 109 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 110 | Communicates with a remote block storage service provider to provide storage. |
| 111 | |
| 112 | Block Store Devices |
| 113 | ------------------- |
| 114 | |
| 115 | - **file_block_store** - stores blocks in file accessed using the standard C file (stdio.h) API. |
| 116 | The file represents a contiguous array of storage blocks. Designed to be used in a POSIX |
| 117 | environment as a virtual storage media. |
| 118 | - **fvb_block_store** - an adapter that uses a UEFI firmware volume block driver to access |
| 119 | storage. Can be used with drivers from the EDK2 project. |
| 120 | - **mock_block_store** - mocked block store for unit testing. |
| 121 | - **null_block_store** - a store with no real storage. Always accepts legal writes and returns |
| 122 | zeros for reads. |
| 123 | - **ram_block_store** - stores blocks in RAM. Intended for test purposes. |
| 124 | - **rpmb_block_store** - it is a Replay Protected Memory Block device |
| 125 | (see `SD Association home page`_) that uses the RPMB frontend to provide RPMB based storage. |
| 126 | - **semihosting_block_store** - it is a block device that can be used on emulators |
| 127 | (FVP, qemu, etc...) or on target platforms where the debugger can provide the file-system |
| 128 | semihosting features (See `this page`_.). Semihosting allows accessing files from the host |
| 129 | environment. This block store uses a single file to represent a contiguous array of storage |
| 130 | blocks. |
| 131 | |
| 132 | Stacked Block Stores |
| 133 | -------------------- |
| 134 | |
| 135 | Partitioned Block Store |
| 136 | ^^^^^^^^^^^^^^^^^^^^^^^ |
| 137 | |
| 138 | To allow multiple higher layer filesystems to share the same storage device, |
| 139 | logical block addresses are partitioned, based on configuration data provided |
| 140 | by a system integrator. The partition configuration data may be read from a |
| 141 | GUID Partition Table (GPT) or from the block storage SP manifest. The |
| 142 | configuration data restricts access to a storage partition to a defined owner. |
| 143 | Each owner is allocated a maximum number of blocks and is given exclusive access |
| 144 | to its own blocks, based on the client ID of the calling client. |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 145 | |
| 146 | Storage Partition Configuration |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 147 | """"""""""""""""""""""""""""""" |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 148 | The block storage service allows a block storage device to be presented as a single storage |
| 149 | partition or as a set of smaller storage partitions. The way that storage is presented is |
| 150 | determined by configuration data prepared by a platform integrator. Each storage partition |
| 151 | presented by a block storage service provider starts at LBA zero. The number of partitions |
| 152 | and their size are defined by configuration data. Configuration data assigns partitions |
| 153 | to owners to enable access to be controlled. If no partition configuration exists for a |
| 154 | requesting client or if an attempt is made to access a block outside of the configured LBA |
| 155 | range, access is denied. The set of storage partitions used for secure block storage will |
| 156 | not necessarily span the entire underlying storage device. A platform integrator is free to |
| 157 | limit the area used for secure block storage to allow the storage device to be used for other |
| 158 | purposes e.g. as a boot source, read by the boot loader during early boot stages. |
| 159 | |
| 160 | Two partition configuration methods will be supported; one where partition configuration data |
| 161 | is read from an SP manifest and the other where configuration is defined by a GUID Partition |
| 162 | Table. Both methods may be used in combination if necessary. Initial implementations will |
| 163 | use the SP manifest configuration method. |
| 164 | |
| 165 | Each partition configuration entry includes an attributes bitmap that conforms to the UEFI |
| 166 | GPT Partition Entry attributes definition (see section 5.3 of the UEFI specification). Bits |
| 167 | 48-63 are reserved for GUID specific use. For partitions labelled with the Secure Block Store |
| 168 | GUID, bits will be defined for: |
| 169 | |
| 170 | - **Read-only** - write and erase operations are forbidden. |
| 171 | |
| 172 | A GPT partition entry includes the PartitionName property which normally holds a human readable |
| 173 | name for the partition. For secure block store partitions, the PartitionName property will |
| 174 | hold the canonical UUID string identifying the owner. An empty string is interpreted as |
| 175 | 'no specific owner' and any client will be granted access. |
| 176 | |
| 177 | Configuration via SP Manifest |
| 178 | """"""""""""""""""""""""""""" |
| 179 | For an SP deployment, the partition configuration may be read from a device tree blob (DTB), |
| 180 | passed as an initialization parameter. Per-partition configuration data comprises the following: |
| 181 | |
| 182 | .. list-table:: |
| 183 | :header-rows: 1 |
| 184 | |
| 185 | * - Config Value |
| 186 | - Description |
| 187 | * - UniquePartitionGUID |
| 188 | - GUID that is unique for a partition entry. |
| 189 | * - StartingLBA |
| 190 | - The storage block address corresponding to LBA zero. |
| 191 | * - EndingLBA |
| 192 | - The last storage block in the contiguous range of blocks. |
| 193 | * - Attributes |
| 194 | - See UEFI specification |
| 195 | * - Owner |
| 196 | - Holds canonical UUID string for owner. |
| 197 | |
| 198 | The partition configuration is included as a sub-node of the block-dev node that includes |
| 199 | configuration values related to the block device. The following is an example of how a block |
| 200 | device and related partitions are defined within a DT based SP manifest:: |
| 201 | |
| 202 | block-dev { |
| 203 | compatible = "tforg,ts-block-dev" |
| 204 | disk-guid = "af9f72de-d71f-4492-b44b-a4b4d96000bf" |
| 205 | |
| 206 | partitions { |
| 207 | compatible = "tforg,ts-block-partitions" |
| 208 | |
| 209 | fwu-meta { |
| 210 | guid = "a6f99e90-7a75-4384-847a-29c9a86c6279" |
| 211 | start-lba = <0x00000000> |
| 212 | end-lba = <0x00000003> |
| 213 | attr = <0x00000000> |
| 214 | owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22" |
| 215 | }; |
| 216 | |
| 217 | fip { |
| 218 | guid = "1eccc9bc-9a5f-43d0-bcd3-466fd21c9a92" |
| 219 | start-lba = <0x00000004> |
| 220 | end-lba = <0x00040003> |
| 221 | attr = <0x00000000> |
| 222 | owner = "afb995cd-9354-4333-9ea2-bd62ccaedb22" |
| 223 | }; |
| 224 | |
| 225 | uefi-var { |
| 226 | guid = "1022a92b-4b4a-47b4-94cb-35faf5a45dc2" |
| 227 | start-lba = <0x00040004> |
| 228 | end-lba = <0x00080003> |
| 229 | attr = <0x00000000> |
| 230 | owner = "ed32d533-99e6-4209-9cc0-2d72cdd998a7" |
| 231 | }; |
| 232 | }; |
| 233 | }; |
| 234 | |
| 235 | Configuration via GUID Partition Table (GPT) |
| 236 | """""""""""""""""""""""""""""""""""""""""""" |
| 237 | The UEFI specification defines a standard layout for physical storage devices where storage |
| 238 | partitions are described by partition entries within the GUID Partition Table. During |
| 239 | initialization, the Block Storage SP will read the GPT and iterate over partition entries, |
| 240 | identifying those with the secure block store partition type GUID. Each entry contains the |
| 241 | following: |
| 242 | |
| 243 | .. list-table:: |
| 244 | :header-rows: 1 |
| 245 | |
| 246 | * - Offset |
| 247 | - Length |
| 248 | - contents |
| 249 | * - 0 |
| 250 | - 16 bytes |
| 251 | - PartitionTypeGUID - Secure Block Store GUID |
| 252 | * - 16 |
| 253 | - 16 bytes |
| 254 | - UniquePartitionGUID |
| 255 | * - 32 |
| 256 | - 8 bytes |
| 257 | - Starting LBA |
| 258 | * - 40 |
| 259 | - 8 bytes |
| 260 | - Ending LBA |
| 261 | * - 48 |
| 262 | - 8 bytes |
| 263 | - Attributes (e.g. read-only) |
| 264 | * - 56 |
| 265 | - 72 bytes |
| 266 | - PartitionName - Holds canonical UUID string for owner. |
| 267 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 268 | Encrypted Block Store |
| 269 | ^^^^^^^^^^^^^^^^^^^^^ |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 270 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 271 | To provide data in rest, and data in transit protection for the stored data using encryption. |
| 272 | The current implementation uses *AES-CBC with ESSIV* encryption, where the encryption key is |
| 273 | derived from the Encryption Root key (ERK). |
| 274 | This way a unique, deterministic, but unpredictable vector is generated for each sector, which |
| 275 | mitigates IV prediction based attacks, like watermarking attack. |
| 276 | To implement the algorithm two keys are derived from the root key and generated with the same |
| 277 | salt value, but with different info: |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 278 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 279 | - **encryption key** - encryption and decryption of the data (AES with CBC block cipher mode) |
| 280 | - **essiv key** - generation of the IV (AES with ECB block cipher mode) |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 281 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 282 | Encrypted Block Store Configuration |
| 283 | """"""""""""""""""""""""""""""""""" |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 284 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 285 | - **ENCRYPTED_BLK_AES_KEY_BITS** - determines the size of the keys derived from the root key |
| 286 | supported values are 128, 192 and 256. |
| 287 | - **ENCRYPTED_BLK_BLOCK_ENCRYPTION_ROOT_KEY** - root key to be used to derive encryption |
| 288 | and ESSIV keys from. |
| 289 | - **ENCRYPTED_BLK_BLOCK_ENCRYPTION_SALT** - Salt value to make impossible for an attacker to |
| 290 | derive the same keys as the ones used for encryption without knowing this value. |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 291 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 292 | Encrypted Block Store Limitations |
| 293 | """"""""""""""""""""""""""""""""" |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 294 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 295 | - Block size of the store must be multiple of the AES block size (16 bytes). |
| 296 | - Encryption root key is currently a configurable vector in the future it should come from a |
| 297 | secure source, like from the Crypto SP or a separate SP responsible for root key storage and |
| 298 | key derivation, but in the current implementation |
| 299 | - AES with CBC block method encrypts a whole block, where the consecutive AES blocks are |
| 300 | interconnected. A drawback of this algorithm is that partial read or write does not |
| 301 | work. To mitigate this limitation at read request the whole block is read and only partial |
| 302 | data is returned, at write request the read-modify-write methodology is used. |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 303 | |
| 304 | -------------- |
| 305 | |
Gabor Toth | 666e2bc | 2024-12-03 15:42:24 +0100 | [diff] [blame] | 306 | .. _`SD Association home page`: https://www.sdcard.org/developers/boot-and-new-security-features/replay-protected-memory-block/ |
| 307 | .. _`this page`: https://developer.arm.com/documentation/dui0203/j/semihosting?lang=en |
| 308 | |
Julian Hall | 1751ce7 | 2022-08-30 13:54:13 +0100 | [diff] [blame] | 309 | *Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.* |
| 310 | |
| 311 | SPDX-License-Identifier: BSD-3-Clause |