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