aboutsummaryrefslogtreecommitdiff
path: root/docs/user_guides/services/tfm_attestation_integration_guide.md
blob: d6085f46652a1b2c9c7e7415ca6be69b38e6e7b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# TF-M Initial Attestation Service Integration Guide

## Introduction
TF-M Initial Attestation Service allows the application to prove the device
identity during an authentication process to a verification entity. The initial
attestation service can create a token on request, which contains a fix set of
device specific data. Device must contain an attestation key pair, which is
unique per device. The token is signed with the private part of attestation key
pair. The public part of the key pair is known by the verification entity. The
public key is used to verify the token authenticity. The data items in the token
used to verify the device integrity and assess its trustworthiness. Attestation
key provisioning is out of scope for the attestation service and is expected to
take part during manufacturing of the device.

## Current service limitations
- **Signing of token** - In the current implementation the token is not properly
signed. Signature is generated according to the
[COSE](https://datatracker.ietf.org/doc/rfc8152/) format. But its actual value
is not a correct ECDSA P256 signature, due to the lack of support of the ECDSA
algorithm in the current implementation of the TF-M Crypto service. A fake
signature is created, which is the concatenation of the token's hash value
twice.

## Claims in the initial attestation token
The initial attestation token is formed of claims. A claim is a data item,
which is represented in a key - value structure. The following fixed set of
claims are included in the token:
- **Challenge**: Input object from caller. Can be a single nonce from server or
hash of nonce and attested data. It is intended to provide freshness to reports
and the caller has responsibility to arrange this. Allowed length: 32, 48,
64 bytes. The claim is modeled to be eventually represented by the EAT standard
claim nonce. Until such a time as that standard exists, the claim will be
represented by a custom claim. Value is encoded as byte string.

- **Instance ID**: It represents the unique identifier of the instance. In the
PSA definition it is a hash of the public attestation key of the instance. The
claim is modeled to be eventually represented by the EAT standard claim UEID of
type GUID. Until such a time as that standard exists, the claim will be
represented by a custom claim  Value is encoded as byte string.

- **Verification service indicator**: Optional, recommended claim. It is used by
a Relying Party to locate a validation service for the token. The value is a
text string that can be used to locate the service or a URL specifying the
address of the service. The claim is modeled to be eventually represented by
the EAT standard claim origination. Until such a time as that standard exists,
the claim will be represented by a custom claim. Value is encoded as text
string.

- **Profile definition**: Optional, recommended claim. It contains the name of a
document that describes the 'profile' of the token, being a full description of
the claims, their usage, verification and token signing. The document name may
include versioning. Custom claim with a value encoded as text string.

- **Implementation ID**: It represents the original implementation signer of the
attestation key and identifies the contract between the report and verification.
A verification service will use this claim to locate the details of the
verification process. Custom claim with a value encoded as byte string.

- **Security lifecycle**: It represents the current lifecycle state of the
instance. Custom claim with a value encoded as an integer.

- **Client ID**: The partition ID of that secure partition or non-secure thread
who called the initial attestation API. Custom claim with a value encoded as a
`signed` integer. Negative number represents non-secure caller, positive numbers
represents secure callers, zero is invalid.

- **HW version**: Optional claim. Globally unique number in EAN-13 format
identifying the GDSII that went to fabrication, HW and ROM. It can be used to
reference the security level of the PSA-ROT via a certification website. Custom
claim with a value is encoded as text string.

- **Boot seed**: It represents a random value created at system boot time that
will allow differentiation of reports from different system sessions. The size
is 32 bytes. Custom claim with a value is encoded as byte string.

- **Software components**: Optional, recommended claim. It represents the
software state of the system. The value of the claim is an array of CBOR map
entries, with one entry per software component within the device. Each map
contains multiple claims that describe evidence about the details of the
software component.

 - **Measurement type**: Optional claim. It represents the role of the software
 component. Value is encoded as short(!) text string.

 - **Measurement value**: It represents a hash of the invariant software
 component in memory at start-up time. The value must be a cryptographic hash
 of 256 bits or stronger. Value is encoded as byte string.

 - **Security epoch**: Optional claim. It represents the security control point
 of the software component. Value is encoded as unsigned integer.

 - **Version**: Optional claim. It represents the issued software version. Value
 is encoded as text string.

 - **Signer ID**: It represents the hash of a signing authority public key.
 Value is encoded as byte string.

 - **Measurement description**: Optional claim. It represents the way in which
 the measurement value of the software component is computed. Value is encoded
 as text string containing an abbreviated description (name) of the measurement
 method.

- **No software measurements**: In the event that the implementation does not
contain any software measurements then the software components claim above can
be omitted but instead it is mandatory to include this claim to indicate this is
a deliberate state. Custom claim a value is encoded as an unsigned integer set
to 1.

## Initial attestation token (IAT) data encoding
The initial attestation token is planned to be aligned with future version of
[Entity Attestation Token](https://tools.ietf.org/html/draft-mandyam-eat-01)
format. The token is encoded according to the
[CBOR](https://tools.ietf.org/html/rfc7049) format and signed according to
[COSE](https://tools.ietf.org/html/rfc8152) standard.

## Code structure
The PSA interface for the Initial Attestation Service is located in
`interface/include`.
The only header to be included by applications that want to use functions from
the PSA API is `psa_initial_attestation.h`.
The TF-M Initial Attestation Service source files are located in
`secure_fw/services/initial_attestation`.
The CBOR library is located in `lib/ext/qcbor` folder.

### Service source files
- CBOR library:
 - `lib/ext/qcbor`: This library is used to create a proper CBOR token. It can
 be used on 32-bit and 64-bit machines. It was designed to suite constrained
 devices with low memory usage and without dynamic memory allocation. It is a
 fork of this external
 [QCBOR library](https://github.com/laurencelundblade/QCBOR).
 - `lib/ext/qcbor/inc/qcbor.h`: Public API documentation of CBOR library.
- COSE library:
 - `lib/t_cose`: This library is used to sign a CBOR token and create the COSE
 header and signature around the initial attestation token. Only a subset of the
 [COSE](https://tools.ietf.org/html/rfc8152) standard is implemented. Only the
 cose_sign1 signature schema is supported.
 - `lib/t_cose/src/t_cose_crypto.h`: Expose an API to bind `t_cose` library with
 available crypto library in the device.
 - `lib/t_cose/src/t_cose_psa_crypto.c`: Implements the exposed API and ports
 `t_cose` to psa_crypto library.
- Initial Attestation Service:
 - `attestation_core.c` : Implements core functionalities such as implementation
 of APIs, retrieval of claims and token creation.
 - `attest_token.c`: Implements the token creation function such as start and
 finish token creation and adding claims to the token.
 - `attestation_crypto_stub.c`: Temporary file, it implements the missing
 psa_crypto APIs.
 - `attestation_key.c`: Get the attestation key from platform layer and register
 it to psa_crypto service for further usage.
 - `tfm_attestation.c`: Implements the SPM abstraction layer, and bind the
 attestation service to the SPM implementation in TF-M project.
 - `tfm_attestation_secure_api.c`: Implements the secure API layer to allow
 other services in the secure domain to request functionalities from the
 attestation service using the PSA API interface.

### Service interface definitions
- **Boot loader interface**: The attestation service might include data in the
token about the distinct software components in the device. This data is
provided by the boot loader and must be encoded in the TLV format, definition
is described below in the boot loader interface paragraph. Possible claims in
the boot status are describe above in the software components paragraph.
- **Hardware abstraction layer**:
  - Headers are located in `platform/include` folder.
   - `tfm_attest_hal.h`: Expose an API to get the following claims: security
   lifecycle, verification service indicator, profile definition.
   - `tfm_plat_boot_seed.h`: Expose an API to get the boot seed claim.
   - `tfm_plat_device_id.h`: Expose an API to get the following claims:
   implementation ID, hardware version, instance ID.
- **SPM interface**:
 - `attestation.h`: Expose an API to bind attestation service to an SPM
 implementation.
- **PSA interface**:
  - `psa_initial_attestation.h`: Public API definition of initial attestation
  service.
- **Crypto interface**:
  - `t_cose_crypto.h`: Expose an API to bind the `t_cose` implementation to any
  cryptographic library.
  - `tfm_plat_crypto_keys.h`: Expose an API to get the attestation key from
  platform layer.

### PSA interface
The TF-M Initial Attestation Service exposes the following PSA interface:
 ``` c
 enum psa_attest_err_t
 psa_initial_attest_get_token(const uint8_t *challenge_obj,
                              uint32_t       challenge_size,
                              uint8_t       *token,
                              uint32_t      *token_size);

enum psa_attest_err_t
psa_initial_attest_get_token_size(uint32_t  challenge_size,
                                  uint32_t *token_size);
```
The caller must allocate a large enough buffer, where the token is going to be
created by Initial Attestation Service. The size of the created token is highly
dependent on the number of software components in the system and the provided
attributes of these.
The `psa_initial_attest_get_token_size()` function can be called to get the
exact size of the created token.

System integrators might need to port these interfaces to a custom secure
partition manager implementation (SPM). Implementation in TF-M project can be
found here:
- `interface/src/tfm_initial_attestation_api.c`: non-secure interface
implementation
- `secure_fw/services/initial_attestation/tfm_attestation_secure_api.c`: secure
interface implementation

### Secure Partition Manager (SPM) interface
The Initial Attestation Service defines the following interface towards the
secure partition manager (SPM). System integrators **must** port this
interface according to their SPM implementation.
```c
enum psa_attest_err_t
attest_get_boot_data(uint8_t major_type, void *ptr, uint32_t len);

enum psa_attest_err_t
attest_get_caller_client_id(int32_t *caller_id);

enum psa_attest_err_t
attest_check_memory_access(void *addr,
                           uint32_t size,
                           enum attest_memory_access access);
```
- `attest_get_boot_data()`:  Service can retrieve the relevant data from shared
memory area between boot loader and runtime software. It might be the case that
only SPM has direct access to the shared memory area, therefore this function
can be used to copy the service related data from shared memory to a local
memory buffer. In TF-M implementation this function must be called during
service initialization phase, because the shared memory region is deliberately
overlapping with secure main stack to spare some memory and reuse this area
during execution. If boot loader is not available in the system to provide
attributes of software components then this function must be implemented in a
way that just initialize service's memory buffer to:
  ```c
  struct shared_data_tlv_header *tlv_header =
          (struct shared_data_tlv_header *)ptr;
  tlv_header->tlv_magic   = 2016;
  tlv_header->tlv_tot_len = sizeof(struct shared_data_tlv_header *tlv_header);
  ```

- `attest_get_caller_client_id()`: Retrieves the ID of the caller thread.
- `attest_check_memory_access()`: Validates the availability and access rights
of memory regions received as input data: challenge object, token buffer, etc.
- `tfm_client.h`: Service relies on the following external definitions, which
must be present or included in this header file:

  ```c
  typedef struct psa_invec {
      const void *base;
      size_t len;
  } psa_invec;

  typedef struct psa_outvec {
      void *base;
      size_t len;
  } psa_outvec;
  ```

### Hardware abstraction layer:
The following API definitions are intended to retrieve the platform specific
claims. System integrators **must** implement these interface according to their
SoC and software design. Detailed definition of the claims are above in the
claims in the initial attestation token paragraph.
- `tfm_attest_hal_get_security_lifecycle()`: Get the security lifecycle of the
device.
- `tfm_attest_hal_get_verification_service()`: Get the verification service
indicator for initial attestation.
- `tfm_attest_hal_get_profile_definition()`: Get the name of the profile
definition document for initial attestation.
- `tfm_plat_get_boot_seed()`: Get the boot seed, which is a constant random
number during a boot cycle.
- `tfm_plat_get_instance_id()`: Get the UEID of the device.
- `tfm_plat_get_implementation_id`: Get the implementation ID of the device.
- `tfm_plat_get_hw_version`: Get the hardware version of the device.

### Boot loader interface
It is **recommended** to have a secure boot loader in the boot chain, which is
capable of measuring the runtime firmware components (calculates the hash value
of firmware images) and provide other attributes of these (version, type, etc).

The shared data between boot loader and runtime software is TLV encoded. The
definition of TLV structure is described in `bl2/include/tfm_boot_status.h`.
The shared data is stored in a well known location in secure internal memory
and this is a contract between boot loader and runtime SW.

The structure of shared data must be the following:
 - At the beginning there must be a header: `struct shared_data_tlv_header`
   This contains a magic number and a size field which covers the entire
   size of the shared data area including this header.
   ```c
   struct shared_data_tlv_header {
       uint16_t tlv_magic;
       uint16_t tlv_tot_len;
   };
   ```
 - After the header there come the entries which are composed from an entry
   header structure: `struct shared_data_tlv_entry` and the data. In the entry
   header is a type field `tlv_type` which identify the consumer of the entry
   in the runtime software and specify the subtype of that data item. There is
   a size field `tlv_len` which covers the size of the entry header and the
   data. After this structure comes the actual data.
   ```c
   struct shared_data_tlv_entry {
       uint16_t tlv_type;
       uint16_t tlv_len;
   };
   ```
 - Arbitrary number and size of data entry can be in the shared memory area.

The table below gives of overview about the `tlv_type` field in the entry
header. The `tlv_type` always composed from a major and minor number. Major
number identifies the addressee in runtime software, which the data entry is
sent to. Minor number used to encode more info about the data entry. The actual
definition of minor number could change per major number. In case of boot
status data, which is going to be processed by initial attestation service
the minor number is split further to two part: `sw_module` and `claim`. The
`sw_module` identifies the SW component in the system which the data item
belongs to and the `claim` part identifies the exact type of the data.

`tlv_type` description:
```
|------------------------------------------------ |
|                  tlv_type (16 bits)             |
|-------------------------------------------------|
|   tlv_major(4 bits)   |   tlv_minor(12 bits)    |
|-------------------------------------------------|
| MAJOR_IAS   | sw_module(6 bits) | claim(6 bits) |
|-------------------------------------------------|
| MAJOR_CORE  |          TBD                      |
|-------------------------------------------------|
```

Overall structure of shared data:
```
---------------------------------------------------------------
| Magic number(uint16_t) | Shared data total length(uint16_t) |
---------------------------------------------------------------
| Major_type(4 bits) | Minor_type(12 bits) | Length(uint16_t) |
---------------------------------------------------------------
|                         Raw data                            |
---------------------------------------------------------------
|                              .                              |
|                              .                              |
|                              .                              |
---------------------------------------------------------------
| Major_type(4 bits) | Minor_type(12 bits) | Length(uint16_t) |
---------------------------------------------------------------
|                         Raw data                            |
---------------------------------------------------------------
```

### Crypto interface
Device **must** contain an asymmetric key pair. The private part of it is used
to sign the initial attestation token. Current implementation supports only the
ECDSA P256 signature over SHA256. The public part of the key pair is used to
create the key identifier (kid) in the unprotected part of the COSE header. The
kid is used by verification entity to look up the corresponding public key to
verify the signature in the token. The `t_cose` part of the initial attestation
service implements the signature generation and kid creation. But the actual
calculation of token's hash and signature is done by the Crypto service in the
device. System integrators might need to re-implement the following functions
if they want to use initial attestation service with a different cryptographic
library than Crypto service:
- `t_cose_crypto_pub_key_sign()`: Calculates the signature over a hash value.
- `t_cose_crypto_get_ec_pub_key()`: Get the public key to create the key
identifier.
- `t_cose_crypto_hash_start()`: Start a multipart hash operation.
- `t_cose_crypto_hash_update()`: Add a message fragment to a multipart hash
operation.
- `t_cose_crypto_hash_finish()`:Finish the calculation of the hash of a message.

Interface needed by verification code:
- `t_cose_crypto_pub_key_verify()`: Verify the signature over a hash value.

#### Key handling
The provisioning of the initial attestation key is out of scope of the service
and this document. It is assumed that device maker provisions the unique
asymmetric key pair during the manufacturing process. The following API is
defined to retrieve the attestation key pair from platform layer. Software
integrators **must** port this interface according to their SoC design and make
sure that key pair is available by Crypto service:
- `tfm_plat_get_initial_attest_key()`: Retrieve the initial attestation key pair
from platform layer.

In TF-M project the attestation key is retrieved by initial attestation service.
The key is registered and unregistered to the Crypto service by attestation
service with `psa_import_key()` and `psa_destroy_key()` API calls for further
usage. See in `attestation_key.c`. In other implementation if the attestation
key is directly retrieved by the Crypto service then this key handling is not
necessary.

 --------------

*Copyright (c) 2018-2019, Arm Limited. All rights reserved.*