Galanakis, Minos | 41f8597 | 2019-09-30 15:56:40 +0100 | [diff] [blame] | 1 | ############################################# |
| 2 | Initial Attestation Service Integration Guide |
| 3 | ############################################# |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 4 | |
| 5 | ************ |
| 6 | Introduction |
| 7 | ************ |
| 8 | TF-M Initial Attestation Service allows the application to prove the device |
| 9 | identity during an authentication process to a verification entity. The initial |
| 10 | attestation service can create a token on request, which contains a fix set of |
| 11 | device specific data. Device must contain an attestation key pair, which is |
| 12 | unique per device. The token is signed with the private part of attestation key |
| 13 | pair. The public part of the key pair is known by the verification entity. The |
| 14 | public key is used to verify the token authenticity. The data items in the token |
| 15 | used to verify the device integrity and assess its trustworthiness. Attestation |
| 16 | key provisioning is out of scope for the attestation service and is expected to |
| 17 | take part during manufacturing of the device. |
| 18 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 19 | *************************************** |
| 20 | Claims in the initial attestation token |
| 21 | *************************************** |
| 22 | The initial attestation token is formed of claims. A claim is a data item, |
| 23 | which is represented in a key - value structure. The following fixed set of |
| 24 | claims are included in the token: |
| 25 | |
Raef Coles | 90b3f00 | 2019-10-09 14:13:35 +0100 | [diff] [blame] | 26 | - **Auth challenge**: Input object from caller. Can be a single nonce from |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 27 | server or hash of nonce and attested data. It is intended to provide |
| 28 | freshness to report and the caller has responsibility to arrange |
| 29 | this. Allowed length: 32, 48, 64 bytes. The claim is modeled to be |
| 30 | eventually represented by the EAT standard claim nonce. Until such a |
| 31 | time as that standard exists, the claim will be represented by a custom |
| 32 | claim. Value is encoded as byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 33 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 34 | - **Instance ID**: It represents the unique identifier of the instance. In |
| 35 | the PSA definition it is a hash of the public attestation key of the |
| 36 | instance. The claim is modeled to be eventually represented by the EAT |
| 37 | standard claim UEID of type GUID. Until such a time as that standard |
| 38 | exists, the claim will be represented by a custom claim Value is encoded |
| 39 | as byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 40 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 41 | - **Verification service indicator**: Optional, recommended claim. It |
| 42 | is used by a Relying Party to locate a validation service for the |
| 43 | token. The value is a text string that can be used to locate the service |
| 44 | or a URL specifying the address of the service. The claim is modelled to |
| 45 | be eventually represented by the EAT standard claim origination. Until |
| 46 | such a time as that standard exists, the claim will be represented by |
| 47 | a custom claim. Value is encoded as text string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 48 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 49 | - **Profile definition**: Optional, recommended claim. It contains the |
| 50 | name of a document that describes the 'profile' of the token, being |
| 51 | a full description of the claims, their usage, verification and token |
| 52 | signing. The document name may include versioning. Custom claim with a |
| 53 | value encoded as text string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 54 | |
Raef Coles | 90b3f00 | 2019-10-09 14:13:35 +0100 | [diff] [blame] | 55 | - **Implementation ID**: Uniquely identifies the underlying immutable PSA |
| 56 | RoT. A verification service can use this claim to locate the details of |
| 57 | the verification process. Such details include the implementation’s origin |
| 58 | and associated certification state. Custom claim with a value encoded as |
| 59 | byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 60 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 61 | - **Client ID**: The partition ID of that secure partition or non-secure |
| 62 | thread who called the initial attestation API. Custom claim with a value |
| 63 | encoded as a `signed` integer. Negative number represents non-secure |
| 64 | caller, positive numbers represents secure callers, zero is invalid. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 65 | |
Raef Coles | 90b3f00 | 2019-10-09 14:13:35 +0100 | [diff] [blame] | 66 | - **Security lifecycle**: It represents the current lifecycle state of |
| 67 | the instance. Custom claim with a value encoded as an integer. |
| 68 | |
| 69 | - **Hardware version**: Optional claim. Globally unique number in EAN-13 |
| 70 | format identifying the GDSII that went to fabrication, HW and ROM. It can |
| 71 | be used to reference the security level of the PSA-ROT via a certification |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 72 | website. Custom claim with a value is encoded as text string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 73 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 74 | - **Boot seed**: It represents a random value created at system boot |
| 75 | time that will allow differentiation of reports from different system |
| 76 | sessions. The size is 32 bytes. Custom claim with a value is encoded as |
| 77 | byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 78 | |
Raef Coles | 90b3f00 | 2019-10-09 14:13:35 +0100 | [diff] [blame] | 79 | - **Software components**: Optional, but required in order to be compliant |
| 80 | with the PSA-SM. It represents the software state of the system. The value |
| 81 | of the claim is an array of CBOR map entries, with one entry per software |
| 82 | component within the device. Each map contains multiple claims that |
| 83 | describe evidence about the details of the software component. |
| 84 | |
| 85 | - **No software measurements**: Optional, but required if no software |
| 86 | component claims are made. In the event that the implementation does not |
| 87 | contain any software measurements then it is mandatory to include this |
| 88 | claim to indicate this is a deliberate state. Custom claim with a value |
| 89 | encoded as an unsigned integer set to 1. |
| 90 | |
| 91 | Each software component claim can include the following properties. Any property |
| 92 | that is not optional must be included: |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 93 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 94 | - **Measurement type**: Optional claim. It represents the role of the |
| 95 | software component. Value is encoded as short(!) text string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 96 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 97 | - **Measurement value**: It represents a hash of the invariant software |
| 98 | component in memory at start-up time. The value must be a cryptographic |
| 99 | hash of 256 bits or stronger. Value is encoded as byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 100 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 101 | - **Version**: Optional claim. It represents the issued software |
| 102 | version. Value is encoded as text string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 103 | |
Raef Coles | 90b3f00 | 2019-10-09 14:13:35 +0100 | [diff] [blame] | 104 | - **Signer ID**: Optional claim, but required in order to be compliant with |
| 105 | the PSA-SM. It represents the hash of a signing authority public key. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 106 | Value is encoded as byte string. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 107 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 108 | - **Measurement description**: Optional claim. It represents the way in |
| 109 | which the measurement value of the software component is computed. Value |
| 110 | is encoded as text string containing an abbreviated description (name) |
| 111 | of the measurement method. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 112 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 113 | ********************************************* |
| 114 | Initial attestation token (IAT) data encoding |
| 115 | ********************************************* |
| 116 | The initial attestation token is planned to be aligned with future version of |
| 117 | `Entity Attestation Token <https://tools.ietf.org/html/draft-mandyam-eat-01>`__ |
| 118 | format. The token is encoded according to the |
| 119 | `CBOR <https://tools.ietf.org/html/rfc7049>`__ format and signed according to |
| 120 | `COSE <https://tools.ietf.org/html/rfc8152>`__ standard. |
| 121 | |
| 122 | ************** |
| 123 | Code structure |
| 124 | ************** |
| 125 | The PSA interface for the Initial Attestation Service is located in |
| 126 | ``interface/include``. The only header to be included by applications that want |
Jamie Fox | cc31d40 | 2019-01-28 17:13:52 +0000 | [diff] [blame] | 127 | to use functions from the PSA API is ``psa/initial_attestation.h``. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 128 | |
| 129 | The TF-M Initial Attestation Service source files are located in |
Ken Liu | 738a4b0 | 2020-06-04 14:52:38 +0800 | [diff] [blame] | 130 | ``secure_fw/partitions/initial_attestation``. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 131 | The CBOR library is located in ``lib/ext/qcbor`` folder. |
| 132 | |
| 133 | Service source files |
| 134 | ==================== |
| 135 | - CBOR library |
| 136 | - ``lib/ext/qcbor`` This library is used to create a proper CBOR token. |
| 137 | It can be used on 32-bit and 64-bit machines. It was designed to suite |
| 138 | constrained devices with low memory usage and without dynamic memory |
| 139 | allocation. |
| 140 | It is a fork of this external `QCBOR library <https://github.com/laurencelundblade/QCBOR>`__. |
| 141 | - ``lib/ext/qcbor/inc/qcbor.h``: Public API documentation of CBOR |
| 142 | library. |
| 143 | |
| 144 | - COSE library: |
| 145 | - ``lib/t_cose``: This library is used to sign a CBOR token and create |
| 146 | the COSE header and signature around the initial attestation token. Only |
| 147 | a subset of the `COSE <https://tools.ietf.org/html/rfc8152>`__ standard |
| 148 | is implemented. Only the cose_sign1 signature schema is supported. |
| 149 | - ``lib/t_cose/src/t_cose_crypto.h``: Expose an API to bind ``t_cose`` |
| 150 | library with available crypto library in the device. |
| 151 | - ``lib/t_cose/src/t_cose_psa_crypto.c``: Implements the exposed API |
Jamie Fox | cc31d40 | 2019-01-28 17:13:52 +0000 | [diff] [blame] | 152 | and ports ``t_cose`` to the PSA Crypto API. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 153 | - Initial Attestation Service: |
| 154 | - ``attestation_core.c`` : Implements core functionalities such as |
| 155 | implementation of APIs, retrieval of claims and token creation. |
| 156 | - ``attest_token.c``: Implements the token creation function such as |
| 157 | start and finish token creation and adding claims to the token. |
| 158 | - ``attestation_key.c``: Get the attestation key from platform layer |
| 159 | and register it to the TF-M Crypto service for further usage. |
| 160 | - ``tfm_attestation.c``: Implements the SPM abstraction layer, and bind |
| 161 | the attestation service to the SPM implementation in TF-M project. |
| 162 | - ``tfm_attestation_secure_api.c``: Implements the secure API layer to |
| 163 | allow other services in the secure domain to request functionalities |
| 164 | from the attestation service using the PSA API interface. |
| 165 | - ``tfm_attestation_req_mngr.c``: Includes the initialization entry of |
| 166 | attestation service and handles attestation service requests in IPC |
| 167 | model. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 168 | |
| 169 | Service interface definitions |
| 170 | ============================= |
| 171 | - **Boot loader interface**: The attestation service might include data |
| 172 | in the token about the distinct software components in the device. This data |
| 173 | is provided by the boot loader and must be encoded in the TLV format, |
| 174 | definition is described below in the boot loader interface paragraph. Possible |
| 175 | claims in the boot status are describe above in the software components |
| 176 | paragraph. |
| 177 | - **Hardware abstraction layer**: |
| 178 | - Headers are located in ``platform/include`` folder. |
| 179 | - ``tfm_attest_hal.h``: Expose an API to get the following claims: |
| 180 | security lifecycle, verification service indicator, profile definition. |
| 181 | - ``tfm_plat_boot_seed.h``: Expose an API to get the boot seed claim. |
| 182 | - ``tfm_plat_device_id.h``: Expose an API to get the following claims: |
| 183 | implementation ID, hardware version, instance ID. |
| 184 | - **SPM interface**: |
| 185 | - ``attestation.h``: Expose an API to bind attestation service to an SPM |
| 186 | implementation. |
| 187 | - **PSA interface**: |
Jamie Fox | cc31d40 | 2019-01-28 17:13:52 +0000 | [diff] [blame] | 188 | - ``psa/initial_attestation.h``: Public API definition of initial |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 189 | attestation service. |
| 190 | - **Crypto interface**: |
| 191 | - ``t_cose_crypto.h``: Expose an API to bind the ``t_cose`` implementation |
| 192 | to any cryptographic library. |
| 193 | - ``tfm_plat_crypto_keys.h``: Expose an API to get the attestation key from |
| 194 | platform layer. |
| 195 | |
| 196 | PSA interface |
| 197 | ============= |
| 198 | The TF-M Initial Attestation Service exposes the following PSA |
| 199 | interface: |
| 200 | |
| 201 | .. code-block:: c |
| 202 | |
Raef Coles | 793574c | 2019-10-09 10:59:42 +0100 | [diff] [blame] | 203 | psa_status_t |
Raef Coles | 70a02da | 2019-10-09 11:32:04 +0100 | [diff] [blame] | 204 | psa_initial_attest_get_token(const uint8_t *auth_challenge, |
| 205 | size_t challenge_size, |
| 206 | uint8_t *token_buf, |
| 207 | size_t token_buf_size, |
| 208 | size_t *token_size); |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 209 | |
Raef Coles | 793574c | 2019-10-09 10:59:42 +0100 | [diff] [blame] | 210 | psa_status_t |
Raef Coles | 70a02da | 2019-10-09 11:32:04 +0100 | [diff] [blame] | 211 | psa_initial_attest_get_token_size(size_t challenge_size, |
| 212 | size_t *token_size); |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 213 | |
Raef Coles | 793574c | 2019-10-09 10:59:42 +0100 | [diff] [blame] | 214 | psa_status_t |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 215 | tfm_initial_attest_get_public_key(uint8_t *public_key, |
| 216 | size_t public_key_buf_size, |
| 217 | size_t *public_key_len, |
| 218 | psa_ecc_curve_t *elliptic_curve_type); |
| 219 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 220 | The caller must allocate a large enough buffer, where the token is going to be |
| 221 | created by Initial Attestation Service. The size of the created token is highly |
| 222 | dependent on the number of software components in the system and the provided |
| 223 | attributes of these. The ``psa_initial_attest_get_token_size()`` function can be |
| 224 | called to get the exact size of the created token. |
| 225 | |
| 226 | System integrators might need to port these interfaces to a custom secure |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 227 | partition manager implementation (SPM). Implementations in TF-M project can be |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 228 | found here: |
| 229 | |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 230 | - ``interface/src/tfm_initial_attestation_func_api.c``: non-secure interface |
| 231 | implementation for library model |
| 232 | - ``interface/src/tfm_initial_attestation_ipc_api.c``: non-secure interface |
| 233 | implementation for IPC model |
Ken Liu | 738a4b0 | 2020-06-04 14:52:38 +0800 | [diff] [blame] | 234 | - ``secure_fw/partitions/initial_attestation/tfm_attestation_secure_api.c``: |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 235 | secure interface implementation |
| 236 | |
| 237 | Secure Partition Manager (SPM) interface |
| 238 | ======================================== |
| 239 | The Initial Attestation Service defines the following interface towards the |
| 240 | secure partition manager (SPM). System integrators **must** port this interface |
| 241 | according to their SPM implementation. |
| 242 | |
| 243 | .. code:: c |
| 244 | |
| 245 | enum psa_attest_err_t |
| 246 | attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len); |
| 247 | |
| 248 | enum psa_attest_err_t |
| 249 | attest_get_caller_client_id(int32_t *caller_id); |
| 250 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 251 | - ``attest_get_boot_data()``: Service can retrieve the relevant data from shared |
| 252 | memory area between boot loader and runtime software. It might be the case |
| 253 | that only SPM has direct access to the shared memory area, therefore this |
| 254 | function can be used to copy the service related data from shared memory to |
| 255 | a local memory buffer. In TF-M implementation this function must be called |
| 256 | during service initialization phase, because the shared memory region is |
| 257 | deliberately overlapping with secure main stack to spare some memory and reuse |
| 258 | this area during execution. If boot loader is not available in the system to |
| 259 | provide attributes of software components then this function must be |
| 260 | implemented in a way that just initialize service's memory buffer to: |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 261 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 262 | .. code-block:: c |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 263 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 264 | struct shared_data_tlv_header *tlv_header = (struct shared_data_tlv_header *)ptr; |
| 265 | tlv_header->tlv_magic = 2016; |
| 266 | tlv_header->tlv_tot_len = sizeof(struct shared_data_tlv_header *tlv_header); |
| 267 | |
| 268 | - ``attest_get_caller_client_id()``: Retrieves the ID of the caller thread. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 269 | - ``tfm_client.h``: Service relies on the following external definitions, which |
| 270 | must be present or included in this header file: |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 271 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 272 | .. code-block:: c |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 273 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 274 | typedef struct psa_invec { |
| 275 | const void *base; |
| 276 | size_t len; |
| 277 | } psa_invec; |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 278 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 279 | typedef struct psa_outvec { |
| 280 | void *base; |
| 281 | size_t len; |
| 282 | } psa_outvec; |
| 283 | |
| 284 | Hardware abstraction layer |
| 285 | ========================== |
| 286 | The following API definitions are intended to retrieve the platform specific |
| 287 | claims. System integrators **must** implement these interface according to their |
| 288 | SoC and software design. Detailed definition of the claims are above |
| 289 | in the claims in the initial attestation token paragraph. |
| 290 | |
| 291 | - ``tfm_attest_hal_get_security_lifecycle()``: Get the security lifecycle of the |
| 292 | device. |
| 293 | - ``tfm_attest_hal_get_verification_service()``: Get the verification |
| 294 | service indicator for initial attestation. |
| 295 | - ``tfm_attest_hal_get_profile_definition()``: Get the name of the profile |
| 296 | definition document for initial attestation. |
| 297 | - ``tfm_plat_get_boot_seed()``: Get the boot seed, which is a constant random |
| 298 | number during a boot cycle. |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 299 | - ``tfm_plat_get_implementation_id``: Get the implementation ID of the |
| 300 | device. |
| 301 | - ``tfm_plat_get_hw_version``: Get the hardware version of the device. |
| 302 | |
| 303 | Boot loader interface |
| 304 | ===================== |
| 305 | It is **recommended** to have a secure boot loader in the boot chain, which is |
| 306 | capable of measuring the runtime firmware components (calculates the hash value |
| 307 | of firmware images) and provide other attributes of these (version, type, etc). |
David Vincze | e13a48b | 2020-01-08 17:42:30 +0100 | [diff] [blame] | 308 | If the used boot loader is not capable of sharing these information with the |
| 309 | runtime software then the ``BOOT_DATA_AVAILABLE`` compiler flag **must** be |
Balint Matyi | 9272a43 | 2020-06-02 07:27:26 +0100 | [diff] [blame] | 310 | set to OFF (see `Related compile time options`_). |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 311 | |
| 312 | The shared data between boot loader and runtime software is TLV encoded. The |
| 313 | definition of TLV structure is described in ``bl2/include/tfm_boot_status.h``. |
| 314 | The shared data is stored in a well known location in secure internal memory |
| 315 | and this is a contract between boot loader and runtime SW. |
| 316 | |
| 317 | The structure of shared data must be the following: |
| 318 | |
| 319 | - At the beginning there must be a header: ``struct shared_data_tlv_header`` |
| 320 | This contains a magic number and a size field which covers the entire size |
| 321 | of the shared data area including this header. |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 322 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 323 | .. code-block:: c |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 324 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 325 | struct shared_data_tlv_header { |
| 326 | uint16_t tlv_magic; |
| 327 | uint16_t tlv_tot_len; |
| 328 | }; |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 329 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 330 | - After the header there come the entries which are composed from an |
| 331 | entry header structure: ``struct shared_data_tlv_entry`` and the data. In |
| 332 | the entry header is a type field ``tlv_type`` which identify the consumer of |
| 333 | the entry in the runtime software and specify the subtype of that data item. |
| 334 | There is a size field ``tlv_len`` which covers the size of the entry header |
| 335 | and the data. After this structure comes the actual data. |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 336 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 337 | .. code-block:: c |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 338 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 339 | struct shared_data_tlv_entry { |
| 340 | uint16_t tlv_type; |
| 341 | uint16_t tlv_len; |
| 342 | }; |
David Vincze | 20c3e4e | 2019-11-11 11:16:06 +0100 | [diff] [blame] | 343 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 344 | - Arbitrary number and size of data entry can be in the shared memory |
| 345 | area. |
| 346 | |
| 347 | The figure below gives of overview about the ``tlv_type`` field in the entry |
| 348 | header. The ``tlv_type`` always composed from a major and minorbnumber. Major |
| 349 | number identifies the addressee in runtime software, which the databentry is |
| 350 | sent to. Minor number used to encode more info about the data entry. The actual |
| 351 | definition of minor number could change per major number. In case of boot |
| 352 | status data, which is going to be processed by initial attestation service |
| 353 | the minor number is split further to two part: ``sw_module`` and ``claim``. The |
| 354 | ``sw_module`` identifies the SW component in the system which the data item |
| 355 | belongs to and the ``claim`` part identifies the exact type of the data. |
| 356 | |
| 357 | ``tlv_type`` description:: |
| 358 | |
| 359 | |------------------------------------------------ | |
| 360 | | tlv_type (16 bits) | |
| 361 | |-------------------------------------------------| |
| 362 | | tlv_major(4 bits) | tlv_minor(12 bits) | |
| 363 | |-------------------------------------------------| |
| 364 | | MAJOR_IAS | sw_module(6 bits) | claim(6 bits) | |
| 365 | |-------------------------------------------------| |
| 366 | | MAJOR_CORE | TBD | |
| 367 | |-------------------------------------------------| |
| 368 | |
| 369 | Overall structure of shared data:: |
| 370 | |
| 371 | --------------------------------------------------------------- |
| 372 | | Magic number(uint16_t) | Shared data total length(uint16_t) | |
| 373 | --------------------------------------------------------------- |
| 374 | | Major_type(4 bits) | Minor_type(12 bits) | Length(uint16_t) | |
| 375 | --------------------------------------------------------------- |
| 376 | | Raw data | |
| 377 | --------------------------------------------------------------- |
| 378 | | . | |
| 379 | | . | |
| 380 | | . | |
| 381 | --------------------------------------------------------------- |
| 382 | | Major_type(4 bits) | Minor_type(12 bits) | Length(uint16_t) | |
| 383 | --------------------------------------------------------------- |
| 384 | | Raw data | |
| 385 | --------------------------------------------------------------- |
| 386 | |
| 387 | Crypto interface |
| 388 | ================ |
| 389 | Device **must** contain an asymmetric key pair. The private part of it is used |
| 390 | to sign the initial attestation token. Current implementation supports only the |
| 391 | ECDSA P256 signature over SHA256. The public part of the key pair is used to |
| 392 | create the key identifier (kid) in the unprotected part of the COSE header. The |
| 393 | kid is used by verification entity to look up the corresponding public key to |
| 394 | verify the signature in the token. The `t_cose` part of the initial attestation |
| 395 | service implements the signature generation and kid creation. But the actual |
| 396 | calculation of token's hash and signature is done by the Crypto service in the |
| 397 | device. System integrators might need to re-implement the following functions |
| 398 | if they want to use initial attestation service with a different cryptographic |
| 399 | library than Crypto service: |
| 400 | |
| 401 | - ``t_cose_crypto_pub_key_sign()``: Calculates the signature over a hash value. |
| 402 | - ``t_cose_crypto_get_ec_pub_key()``: Get the public key to create the key |
| 403 | identifier. |
| 404 | - ``t_cose_crypto_hash_start()``: Start a multipart hash operation. |
| 405 | - ``t_cose_crypto_hash_update()``: Add a message fragment to a multipart hash |
| 406 | operation. |
| 407 | - ``t_cose_crypto_hash_finish()``:Finish the calculation of the hash of a |
| 408 | message. |
| 409 | |
| 410 | Interface needed by verification code: |
| 411 | |
| 412 | - ``t_cose_crypto_pub_key_verify()``: Verify the signature over a hash value. |
| 413 | |
| 414 | Key handling |
| 415 | ------------ |
| 416 | The provisioning of the initial attestation key is out of scope of the service |
| 417 | and this document. It is assumed that device maker provisions the unique |
| 418 | asymmetric key pair during the manufacturing process. The following API is |
| 419 | defined to retrieve the attestation key pair from platform layer. Software |
| 420 | integrators **must** port this interface according to their SoC design and make |
| 421 | sure that key pair is available by Crypto service: |
| 422 | |
| 423 | - ``tfm_plat_get_initial_attest_key()``: Retrieve the initial attestation key |
| 424 | pair from platform layer. |
| 425 | |
| 426 | In TF-M project the attestation key is retrieved by initial attestation service. |
| 427 | The key is registered and unregistered to the Crypto service by attestation |
| 428 | service with ``psa_import_key()`` and ``psa_destroy_key()`` API calls for |
| 429 | further usage. See in ``attestation_key.c``. In other implementation if the |
| 430 | attestation key is directly retrieved by the Crypto service then this key |
| 431 | handling is not necessary. |
| 432 | |
Tamas Ban | 01f64c5 | 2019-08-26 13:46:21 +0100 | [diff] [blame] | 433 | Initial Attestation Service compile time options |
| 434 | ================================================ |
| 435 | There is a defined set of flags that can be used to compile in/out certain |
| 436 | service features. The ``CommonConfig.cmake`` file sets the default values of |
| 437 | those flags. The list of flags are: |
| 438 | |
| 439 | - ``ATTEST_INCLUDE_OPTIONAL_CLAIMS``: Include also the optional claims to the |
Balint Matyi | 9272a43 | 2020-06-02 07:27:26 +0100 | [diff] [blame] | 440 | attestation token. Default value: ON. |
Tamas Ban | abea89d | 2020-01-15 13:29:25 +0000 | [diff] [blame] | 441 | - ``ATTEST_INCLUDE_TEST_CODE``: Test code is removed from COSE library and from |
Balint Matyi | 9272a43 | 2020-06-02 07:27:26 +0100 | [diff] [blame] | 442 | attestation test suite if it is OFF. Its default value depends on the build |
| 443 | type. It is ON if build type is ``Debug``, otherwise OFF (different kinds |
Tamas Ban | abea89d | 2020-01-15 13:29:25 +0000 | [diff] [blame] | 444 | of ``Release`` builds). |
| 445 | - ``ATTEST_INCLUDE_COSE_KEY_ID``: COSE key-id is an optional field in the COSE |
| 446 | unprotected header. Key-id is calculated and added to the COSE header based |
Balint Matyi | 9272a43 | 2020-06-02 07:27:26 +0100 | [diff] [blame] | 447 | on the value of this flag. Default value: OFF. |
Balint Matyi | 95f58eb | 2020-05-22 08:52:32 +0100 | [diff] [blame] | 448 | - ``ATTEST_CLAIM_VALUE_CHECK``: Check attestation claims against hard-coded |
| 449 | values found in ``platform/ext/common/template/attest_hal.c``. Default value |
| 450 | is OFF. Set to ON in a platform's CMake file if the attest HAL is not yet |
| 451 | properly ported to it. |
Tamas Ban | 01f64c5 | 2019-08-26 13:46:21 +0100 | [diff] [blame] | 452 | |
David Vincze | e13a48b | 2020-01-08 17:42:30 +0100 | [diff] [blame] | 453 | Related compile time options |
| 454 | ---------------------------- |
| 455 | - ``BOOT_DATA_AVAILABLE``: The boot data is expected to be present in the shared |
Balint Matyi | 9272a43 | 2020-06-02 07:27:26 +0100 | [diff] [blame] | 456 | data area between the boot loader and the runtime firmware when it's ON. |
| 457 | Otherwise, when it's OFF does not check the content of the shared data area. |
David Vincze | e13a48b | 2020-01-08 17:42:30 +0100 | [diff] [blame] | 458 | Also assume that the TLV header is present and valid (the magic number is |
| 459 | correct) and there are no other data entries. Its default value depends on |
| 460 | the BL2 flag. |
| 461 | |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 462 | ************ |
| 463 | Verification |
| 464 | ************ |
| 465 | The initial attestation token is verified by the attestation test suite in |
| 466 | ``test/suites/attestation``. The test suite is responsible for verifying the |
| 467 | token signature and parsing the token to verify its encoding and the presence of |
| 468 | the mandatory claims. This test suite can be executed on the device. It is part |
| 469 | of the regression test suite. When the user builds TF-M with any of the |
| 470 | ``ConfigRegression*.cmake`` configurations then this test is executed |
| 471 | automatically. The test suite is configurable in the |
| 472 | ``test/suites/attestation/attest_token_test_values.h`` header file. In this file |
| 473 | there are two attributes for each claim which are configurable (more details |
| 474 | in the header file): |
| 475 | |
| 476 | - Requirements of presence: optional or mandatory |
| 477 | - Expected value: Value check can be disabled or expected value can be provided |
| 478 | here. |
| 479 | |
| 480 | There is another possibility to verify the attestation token. This addresses |
| 481 | the off-device testing when the token is already retrieved from the device and |
| 482 | verification is done on the requester side. There is a Python script for this |
| 483 | purpose in ``tools/iat-verifier``. It does the same checking as the |
| 484 | attestation test suite. The following steps describe how to simulate an |
| 485 | off-device token verification on a host computer. It is described how to |
| 486 | retrieve an initial attestation token when TF-M code is executed on FVP |
| 487 | and how to use the iat_verifier script to check the token. This example assumes |
| 488 | that user has license for DS-5 and FVP models: |
| 489 | |
| 490 | - Build TF-M with any of the ``ConfigRegression*.cmake`` build configurations |
| 491 | for MPS2 AN521 platform. More info in |
Minos Galanakis | e409401 | 2020-06-12 14:25:34 +0100 | [diff] [blame] | 492 | :doc:`tfm_build_instruction </docs/getting_started/tfm_build_instruction>`. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 493 | - Lunch FVP model in DS-5. More info in |
Minos Galanakis | e409401 | 2020-06-12 14:25:34 +0100 | [diff] [blame] | 494 | :doc:`tfm_user_guide </docs/getting_started/tfm_user_guide>`. |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 495 | - Set a breakpoint in ``test/suites/attestation/attest_token_test.c`` |
| 496 | in ``decode_test_internal(..)`` after the ``token_main_alt(..)`` returned, |
| 497 | i.e. on line 859. Execute the code in the model until the breakpoint hits |
| 498 | second time. At this point the console prints the following message: |
| 499 | ``ECDSA signature test of attest token``. |
| 500 | - At this point the token resides in the model memory and can be dumped to host |
| 501 | computer. |
| 502 | - The ADDRESS and SIZE attributes of the initial attestation token is stored in |
| 503 | the ``completed_token`` local variable. Their value can be extracted in the |
| 504 | ``(x)=Variables`` debug window. |
| 505 | - Apply this command in the ``Commands`` debug window to dump the token in |
| 506 | binary format to the host computer: |
| 507 | ``dump memory <PATH>/iat_01.cbor <ADDRESS> +<SIZE>`` |
| 508 | - Execute this command on the host computer to verify the token: |
David Hu | 470c9aa | 2019-12-06 10:31:43 +0800 | [diff] [blame] | 509 | ``check_iat -p -K -k platform/ext/common/template/tfm_initial_attestation_key.pem <PATH>/iat_01.cbor`` |
Tamas Ban | daa4c6e | 2019-07-01 12:39:00 +0100 | [diff] [blame] | 510 | - Documentation of the iat-verifier can be found |
| 511 | :doc:`here </tools/iat-verifier/README>`. |
| 512 | |
Gyorgy Szing | db9783c | 2019-04-17 21:08:48 +0200 | [diff] [blame] | 513 | -------------- |
| 514 | |
Tamas Ban | abea89d | 2020-01-15 13:29:25 +0000 | [diff] [blame] | 515 | *Copyright (c) 2018-2020, Arm Limited. All rights reserved.* |