| UEFI SMM Services |
| ================= |
| The Trusted Services project provides support for UEFI System Management Mode (SMM) services via the |
| SMM Gateway secure partition. The SMM Gateway adopts the API Gateway design pattern, popular in |
| microservices architecture. The pattern decouples clients from backend service providers using an |
| API gateway that presents a domain specific interface to clients while delegating operations to a |
| set of backend microservices. An API gateway will typically use multiple backend services and may |
| perform protocol translation while presenting a single service entry point for clients. The SMM |
| Gateway works in a similar manner - clients access SMM services using standard SMM protocol messages, |
| carried by an RPC mechanism. Service requests are forwarded by the SMM Gateway to backend service |
| providers for operations such as secure persistent storage and signature verification. |
| |
| SMM Gateway is intended to be used on non-EDK2 platforms as an alternative to the EDK2 StandaloneMM |
| (StMM) component. The current SMM Gateway version only supports the SMM Variable service. Additional |
| SMM service providers may be added to SMM Gateway if required. By deliberately limiting functionality |
| and exploiting backend services, the SMM Gateway SP can be significantly lighter-weight than StMM. |
| This option is intended to be used on more resource constrained devices that tend to use u-boot. |
| There is of course the possibility that other SMM services will need to be supported in the future. |
| In such cases, a judgement should be made as to whether StMM should be used rather than extending the SP. |
| |
| .. uml:: uml/SmmGatewayOverview.puml |
| |
| SMM Variable Service |
| -------------------- |
| Overview |
| '''''''' |
| UEFI Variable support is provided by the *smm_variable* service provider component. This service provider |
| is structured in the same way as other service providers within the TS project. Features of this |
| component are: |
| |
| * Source file location: ``components/service/uefi/smm_variable`` |
| * Public interface definitions: ``protocols/service/smm_variable`` |
| * Can be used with any RPC layer - not tied to MM Communicate RPC. |
| * Volatile and non-volatile storage is accessed via instances of the common *storage_backend* interface. |
| |
| The *smm-gateway/opteesp* and *smm-gateway/sp* deployments integrate the *smm_variable* service provider with the following: |
| |
| * An MM Communicate based RPC endpoint. |
| * A *mock_store* instance for volatile variables. |
| * A *secure_storage_client* for non-volatile variables. |
| * A *crypto client* for signature verification. |
| |
| During SP initialization, the *smm-gateway* uses pre-configured information to discover a backend secure |
| storage SP for NV storage and a crypto SP to verify signatures needed for UEFI variable authentication. |
| Crypto SP is accessible only if UEFI_AUTH_VAR is enabled. |
| |
| The following diagram illustrates how the *smm_variable* service provider is integrated into the *smm-gateway*. |
| |
| .. image:: image/smm-gateway-layers.svg |
| |
| Because the *smm_variable* service provider is independent of any particular environment, alternative deployments |
| are possible e.g. |
| |
| * *smm_variable* service provider running within a GP TA with storage off-loaded to the GP TEE Internal API. |
| * *smm_variable* service provider running within a secure enclave with its own internal flash storage. |
| |
| Supported Functions |
| ''''''''''''''''''' |
| The *smm_variable* service provider supports the following functions: |
| |
| .. list-table:: |
| :header-rows: 1 |
| |
| * - SMM Variable Function |
| - Purpose |
| - Backend service interaction |
| * - SMM_VARIABLE_FUNCTION_GET_VARIABLE |
| - Get variable data identified by GUID/name. |
| - Query index and get object from appropriate storage backend. |
| * - SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME |
| - Called multiple times to enumerate stored variables. |
| - Find variable in index and return next. |
| * - SMM_VARIABLE_FUNCTION_SET_VARIABLE |
| - Adds a new variable or updates an existing one. |
| - | Sets object in storage backend and if necessary, updates index |
| | and syncs to storage. |
| * - SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO |
| - Returns information about the variable store. |
| - Iterates over stored variables to determine space used. |
| * - SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE |
| - Called by OS when boot phase is complete. |
| - | Updates view of runtime state held by smm_variable service provider. |
| | State variable used when implementing state dependent access control. |
| * - SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET |
| - | Set constraints that are checked on the SetVariable operation. |
| | Allows a platform to set check policy. |
| - | Variable index holds variable check constraints object for each variable. |
| | This is updated by this function. |
| * - SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET |
| - Get the variable check constraints. |
| - Reads the variable check constraints object. |
| * - SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE |
| - | Returns the maximum variable data size, excluding any |
| | auth header. |
| - | Considers size constraints imposed by backend stores and RPC response |
| | payload constraints. |
| |
| Supported Variable Attributes |
| ''''''''''''''''''''''''''''' |
| The following variable attributes are supported: |
| |
| .. list-table:: |
| :widths: 3 1 3 |
| :header-rows: 1 |
| |
| * - SMM Variable Attribute |
| - Support |
| - Comment |
| * - EFI_VARIABLE_NON_VOLATILE |
| - yes |
| - Determines which storage backend is used. |
| * - EFI_VARIABLE_BOOTSERVICE_ACCESS |
| - yes |
| - Boot service access controlled by smm_variable service provider. |
| * - EFI_VARIABLE_RUNTIME_ACCESS |
| - yes |
| - Runtime access controlled by smm_variable service provider. |
| * - EFI_VARIABLE_HARDWARE_ERROR_RECORD |
| - no |
| - If the attribute contains this value, VariableName and VendorGuid must comply with the rules |
| stated in Section 8.2.4.2 and Appendix P of the standard. |
| * - EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
| - no |
| - DEPRECATED |
| * - EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS |
| - no |
| - Authentication with EFI_VARIABLE_AUTHENTICATION_3 descriptor is enabled. |
| * - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
| - yes |
| - Authentication with EFI_VARIABLE_AUTHENTICATION_2 descriptor is enabled. |
| * - EFI_VARIABLE_APPEND_WRITE |
| - yes |
| - Implemented by overwriting entire variable data. |
| |
| Limitations |
| ''''''''''' |
| |
| .. list-table:: |
| :header-rows: 1 |
| |
| * - Description |
| - Value |
| * - Maximum size of a single variable |
| - 4096 bytes |
| * - Supported type of signature list element |
| - DER-encoded X.509 certificates |
| * - Supported type of public keys |
| - DER-encoded SignedData structure per PKCS#7 version 1.5, with or without a DER-encoded |
| ContentInfo structure per PKCS#7 version 1.5. |
| |
| Variable authentication |
| ''''''''''''''''''''''' |
| |
| UEFI variable authentication is a method to ensure that a UEFI variable can only be modified |
| by those who has proper rights. This restricts only the writing of these variables, while reading |
| is only limited by the state of the system (boot versus runtime access). |
| |
| Key Store Variables |
| ``````````````````` |
| Key Store variables store authentication keys, and have predefined special names to specify the |
| keys scope (area of effect). When a write access to a variable with an active |
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is being made, the signature part of |
| the write access will be verified against the appropriate key Store variable. |
| Access will only be granted if the signature is valid. |
| |
| The following table lists which Key Store variables defined by the UEFI standard are implemented. |
| |
| .. list-table:: |
| :header-rows: 1 |
| |
| * - Variable name |
| - Description |
| - Supported |
| * - Platform Key (PK) |
| - Root of trust. If it is not set the authentication is disabled, all write requests are successful. |
| - yes |
| * - Key Exchange Key Database (KEK) |
| - Protects key store databases from unauthorized modifications. |
| - yes |
| * - Signature Database (db) |
| - If a variable write request is signed by the public key whose private pair is |
| stored here the authentication will pass. |
| - yes |
| * - Blacklist Signature Database (dbx) |
| - Contains signatures of software that must not run on the platform. |
| - no |
| * - Authorized Recovery Signature Database (dbr) |
| - Contains signatures of software that can be run for recovery. |
| - no |
| * - Timestamp Signature Database (dbt) |
| - Same as db, but the timestamp of the certificate is also verified. |
| - no |
| |
| There is no support for initializing the values of the read-only global variables containing |
| default values of the key store variables (e.g. PKDefault, KEKDefault, etc.). |
| |
| The following diagram shows variable authentication hierarchy. |
| |
| *A → B means A has the right to verify write request to B* |
| |
| .. uml:: |
| |
| @startuml |
| [PK] --> [PK] |
| [PK] --> [KEK] |
| [PK] --> [db] |
| [KEK] --> [db] |
| [db] --> [Common Variable] |
| @enduml |
| |
| Authenticated Variable Lifecycle |
| ```````````````````````````````` |
| |
| .. uml:: |
| |
| @startuml |
| |
| start |
| if (Is authentication enabled?) |
| if (Enable authentication?) then (yes) |
| :Key Provision |
| {{ |
| hide empty description |
| |
| state "Set PK" as keyprovision1 |
| state "Set KEK (write request must be signed by PK)" as keyprovision2 |
| state "Set db (write request must be signed with PK or KEK)" as keyprovision3 |
| |
| keyprovision1 --> keyprovision2 |
| keyprovision2 --> keyprovision3 |
| }} |
| ; |
| endif |
| else (yes) |
| switch (Request) |
| case (Clear store\n(disable authentication)) |
| :Clear Store |
| {{ |
| hide empty description |
| |
| state "Delete PK (write request must be signed with PK)" as delete1 |
| state "Delete KEK or db (authentication is disabled, so signature is not verified)" as delete2 |
| |
| delete1 --> delete2 |
| }} |
| ; |
| case (Update keys) |
| :Key Update |
| {{ |
| hide empty description |
| |
| state "Set PK (write request must be signed by original PK)" as keyupdate1 |
| state "Set KEK (write request must be signed by new PK)" as keyupdate2 |
| state "Set db (write request must be signed with new PK or new KEK)" as keyupdate3 |
| |
| keyupdate1 --> keyupdate2 |
| keyupdate2 --> keyupdate3 |
| }} |
| ; |
| case (Reset factory keys) |
| |
| skinparam partitionBorderColor red |
| partition "**NOT IMPLEMENTED**" { |
| switch (Recovery method) |
| case () |
| :Using Setup Mode |
| {{ |
| hide empty description |
| |
| state "Enter Setup Mode to disable authentication" as recovery1 |
| state "Delete PK, KEK, db (signatures are not verified in this mode)" as recovery2 |
| state "Leave setup mode, but authentication is still disabled, because PK is empty" as recovery3 |
| |
| recovery1 -->recovery2 |
| recovery2 -->recovery3 |
| }} |
| ; |
| case () |
| :Using default keystores (PKdefault, KEKDefault, dbDefault); |
| |
| endswitch |
| } |
| |
| case(None) |
| endswitch |
| endif |
| |
| end |
| |
| @enduml |
| |
| Variable structure |
| `````````````````` |
| |
| .. image:: image/uefi-variable-structure.svg |
| |
| | |
| |
| * The elements of the signature verification are stored in or calculated from the fields of the variables: |
| #. Hash: Calculated on Name, GUID, Attributes, Timestamp, Payload fields of the write request |
| #. Public Key: Extracted from the 'Sign. Data' element of the Signature List field in the Payload |
| of the variable responsible for authenticating the request |
| (e.g. in case of KEK request, it will be extracted from PK) |
| #. Signature: Extracted from the 'CertData' field of the write request. |
| |
| SMM Variable Tests |
| '''''''''''''''''' |
| The following test components exist for the SMM Variable service: |
| |
| .. list-table:: |
| :header-rows: 1 |
| |
| * - Test Component |
| - Description |
| - Included in deployments |
| * - ``component/service/uefi/smm_variable/backend/test`` |
| - | Component tests for the variable_index and variable_store backend |
| | components. Can be run in a native PC environment. |
| - ``deployments/component-test/*`` |
| * - ``component/service/uefi/smm_variable/test/service`` |
| - | End-to-end service level tests that call service operations from |
| | the perspective of a client. Can be run in a native PC environment |
| | or on the Arm target platform. |
| - | ``deployments/ts-service-test/*`` |
| | ``deployments/uefi-test/*`` |
| |
| SMM Gateway Build Configuration |
| ------------------------------- |
| The smm-gateway SP image may be built using the default configuration parameters defined |
| within relevant source files. In practice, it is likely that at least some configuration |
| values will need to be overridden. The following table lists build-time configuration |
| parameters that may be overridden by global C pre-processor defines. |
| |
| .. list-table:: |
| :widths: 2 2 2 1 |
| :header-rows: 1 |
| |
| * - Config define |
| - Usage |
| - File |
| - Default value |
| * - SMM_GATEWAY_MAX_UEFI_VARIABLES |
| - Maximum number of variables |
| - ``deployments/smm-gateway/common/smm_gateway.c`` |
| - 40 |
| * - UEFI_MAX_VARIABLE_SIZE |
| - Maximum size of the uefi variables in bytes |
| - ``components/service/uefi/smm_variable/backend/uefi_variable_store.c`` |
| - 4096 |
| * - SMM_GATEWAY_NV_STORE_SN |
| - The service ID for the backend NV variable store |
| - ``deployments/smm-gateway/common/smm_gateway.c`` |
| - Protected Storage SP |
| * - SMM_GATEWAY_CRYPTO_SN |
| - The service ID for the crypto backend |
| - ``deployments/smm-gateway/common/smm_gateway.c`` |
| - Crypto SP |
| * - UEFI_AUTH_VAR |
| - Enables or disables UEFI variable authentication |
| - ``components/service/uefi/smm_variable/backend/uefi_variable_store.c`` |
| - OFF |
| |
| MM Communicate RPC Layer |
| ------------------------ |
| To maintain compatibility with existing SMM service clients, an MM Communicate based RPC |
| layer has been developed that uses the same 'carveout' buffer scheme as StMM. When SMM |
| Gateway is used instead of StMM, existing SMM variable clients should interoperate seamlessly. |
| The MM Communicate RPC components implement the standard TS RPC interfaces and can be used as |
| a general purpose RPC for calls from normal world to secure world. The following MM Communicate |
| RPC components have been added: |
| |
| * ``components/rpc/mm_communicate/endpoint/sp`` - an RPC endpoint that handles FFA direct |
| calls with MM Communicate and SMM message carried in a shared 'carveout' buffer. Call requests |
| are demultiplexed to the appropriate service interface based on the service GUID carried in |
| the MM Communicate header. Suitable for use in SP deployments. |
| * ``components/rpc/mm_communicate/caller/linux`` - an RPC caller that calls service operations |
| associated with the destination service interface from Linux user-space. Uses the MM Communicate |
| protocol, sent over FFA using the Debug FFA kernel driver. Service level tests that run against |
| the SMM Gateway use this RPC caller for invoking SMM service operations. |
| |
| The following register mapping is assumed for FFA based direct calls to an SP that handles the MM |
| Communicate RPC protocol: |
| |
| .. list-table:: |
| :widths: 1 2 2 2 |
| :header-rows: 1 |
| |
| * - Registers |
| - FF-A layer |
| - MM_COMMUNICATE Request |
| - MM_COMMUNICATE Response |
| * - W0 |
| - Function ID |
| - | FFA_MSG_SEND_DIRECT_REQ |
| | (0x8400006F/0xC400006F) |
| - | FFA_MSG_SEND_DIRECT_RESP |
| | (0x84000070/0xC4000070) |
| * - W1 |
| - Source/Destination ID |
| - Source/Destination ID |
| - Source/Destination ID |
| * - W2/X2 |
| - Reserved |
| - 0x00000000 |
| - 0x00000000 |
| * - W3/X3 |
| - Parameter[0] |
| - Data offset in the MM communication buffer |
| - SUCCESS/[MM communicate error code] |
| * - W4/X4 |
| - Parameter[1] |
| - 0x00000000 |
| - 0x00000000 |
| * - W5/X5 |
| - Parameter[2] |
| - 0x00000000 |
| - 0x00000000 |
| * - W6/X6 |
| - Parameter[3] |
| - 0x00000000 |
| - 0x00000000 |
| * - W7/X7 |
| - Parameter[4] |
| - 0x00000000 |
| - 0x00000000 |
| |
| -------------- |
| |
| *Copyright (c) 2021-2024, Arm Limited and Contributors. All rights reserved.* |
| |
| SPDX-License-Identifier: BSD-3-Clause |