1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <string.h>
9 
10 #include "psa/error.h"
11 #include "psa/client.h"
12 #include "psa/initial_attestation.h"
13 #include "psa/crypto.h"
14 #include "attest.h"
15 
16 #include "array.h"
17 #include "psa/framework_feature.h"
18 #include "psa/service.h"
19 #include "psa_manifest/tfm_initial_attestation.h"
20 #include "region_defs.h"
21 #include "tfm_attest_defs.h"
22 
23 #define ECC_P256_PUBLIC_KEY_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(256)
24 
25 typedef psa_status_t (*attest_func_t)(const psa_msg_t *msg);
26 
27 int32_t g_attest_caller_id;
28 
29 #if PSA_FRAMEWORK_HAS_MM_IOVEC == 1
psa_attest_get_token(const psa_msg_t * msg)30 static psa_status_t psa_attest_get_token(const psa_msg_t *msg)
31 {
32     psa_status_t status;
33     const void *challenge_buff;
34     void *token_buff;
35     size_t challenge_size;
36     size_t token_buff_size;
37     size_t token_size;
38 
39     token_buff_size = msg->out_size[0];
40     challenge_size = msg->in_size[0];
41 
42     if (challenge_size > PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64
43         || challenge_size == 0 || token_buff_size == 0) {
44         return PSA_ERROR_INVALID_ARGUMENT;
45     }
46 
47     /* store the client ID here for later use in service */
48     g_attest_caller_id = msg->client_id;
49 
50     challenge_buff = psa_map_invec(msg->handle, 0);
51     token_buff = psa_map_outvec(msg->handle, 0);
52 
53     status = initial_attest_get_token(challenge_buff, challenge_size,
54                                       token_buff, token_buff_size, &token_size);
55     if (status == PSA_SUCCESS) {
56         psa_unmap_outvec(msg->handle, 0, token_size);
57     }
58 
59     return status;
60 }
61 #else /* PSA_FRAMEWORK_HAS_MM_IOVEC == 1 */
62 /* Buffer to store the created attestation token. */
63 static uint8_t token_buff[PSA_INITIAL_ATTEST_TOKEN_MAX_SIZE];
64 
psa_attest_get_token(const psa_msg_t * msg)65 static psa_status_t psa_attest_get_token(const psa_msg_t *msg)
66 {
67     psa_status_t status = PSA_SUCCESS;
68     uint8_t challenge_buff[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64];
69     uint32_t bytes_read = 0;
70     size_t challenge_size;
71     size_t token_buff_size;
72     size_t token_size;
73 
74     challenge_size = msg->in_size[0];
75     token_buff_size = msg->out_size[0] < sizeof(token_buff) ?
76                                           msg->out_size[0] : sizeof(token_buff);
77 
78     if (challenge_size > PSA_INITIAL_ATTEST_CHALLENGE_SIZE_64
79         || challenge_size == 0 || token_buff_size == 0) {
80         return PSA_ERROR_INVALID_ARGUMENT;
81     }
82 
83     /* store the client ID here for later use in service */
84     g_attest_caller_id = msg->client_id;
85 
86     bytes_read = psa_read(msg->handle, 0, challenge_buff, challenge_size);
87     if (bytes_read != challenge_size) {
88         return PSA_ERROR_GENERIC_ERROR;
89     }
90 
91     status = initial_attest_get_token(challenge_buff, challenge_size,
92                                       token_buff, token_buff_size, &token_size);
93     if (status == PSA_SUCCESS) {
94         psa_write(msg->handle, 0, token_buff, token_size);
95     }
96 
97     return status;
98 }
99 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC == 1 */
100 
psa_attest_get_token_size(const psa_msg_t * msg)101 static psa_status_t psa_attest_get_token_size(const psa_msg_t *msg)
102 {
103     psa_status_t status = PSA_SUCCESS;
104     size_t challenge_size;
105     size_t token_size;
106     size_t bytes_read = 0;
107 
108     if (msg->in_size[0] != sizeof(challenge_size)
109         || msg->out_size[0] != sizeof(token_size)) {
110         return PSA_ERROR_INVALID_ARGUMENT;
111     }
112 
113     /* store the client ID here for later use in service */
114     g_attest_caller_id = msg->client_id;
115 
116     bytes_read = psa_read(msg->handle, 0,
117                           &challenge_size, msg->in_size[0]);
118     if (bytes_read != sizeof(challenge_size)) {
119         return PSA_ERROR_INVALID_ARGUMENT;
120     }
121 
122     status = initial_attest_get_token_size(challenge_size, &token_size);
123     if (status == PSA_SUCCESS) {
124         psa_write(msg->handle, 0, &token_size, sizeof(token_size));
125     }
126 
127     return status;
128 }
129 
tfm_attestation_service_sfn(const psa_msg_t * msg)130 psa_status_t tfm_attestation_service_sfn(const psa_msg_t *msg)
131 {
132     switch (msg->type) {
133     case TFM_ATTEST_GET_TOKEN:
134         return psa_attest_get_token(msg);
135     case TFM_ATTEST_GET_TOKEN_SIZE:
136         return psa_attest_get_token_size(msg);
137     default:
138         return PSA_ERROR_NOT_SUPPORTED;
139     }
140 
141     return PSA_ERROR_GENERIC_ERROR;
142 }
143 
attest_partition_init(void)144 psa_status_t attest_partition_init(void)
145 {
146     return attest_init();
147 }
148