10f9159b7SSoby Mathew /*
242cf6026SJuan Pablo Conde * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
3*6a88ec8bSRaghu Krishnamurthy * Copyright (c) 2024, NVIDIA Corporation. All rights reserved.
40f9159b7SSoby Mathew *
50f9159b7SSoby Mathew * SPDX-License-Identifier: BSD-3-Clause
60f9159b7SSoby Mathew */
742cf6026SJuan Pablo Conde #include <errno.h>
80f9159b7SSoby Mathew #include <stdint.h>
90f9159b7SSoby Mathew #include <string.h>
101d0ca40eSJavier Almansa Sobrino
110f9159b7SSoby Mathew #include <common/debug.h>
120f9159b7SSoby Mathew #include <lib/spinlock.h>
130f9159b7SSoby Mathew #include <lib/xlat_tables/xlat_tables_v2.h>
140f9159b7SSoby Mathew #include <plat/common/platform.h>
150f9159b7SSoby Mathew #include "rmmd_private.h"
16*6a88ec8bSRaghu Krishnamurthy #include <services/rmm_el3_token_sign.h>
17*6a88ec8bSRaghu Krishnamurthy #include <smccc_helpers.h>
180f9159b7SSoby Mathew
190f9159b7SSoby Mathew static spinlock_t lock;
200f9159b7SSoby Mathew
210f9159b7SSoby Mathew /* For printing Realm attestation token hash */
220f9159b7SSoby Mathew #define DIGITS_PER_BYTE 2UL
230f9159b7SSoby Mathew #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL
240f9159b7SSoby Mathew #define BYTES_PER_LINE_BASE 4UL
250f9159b7SSoby Mathew
print_challenge(uint8_t * hash,size_t hash_size)260f9159b7SSoby Mathew static void print_challenge(uint8_t *hash, size_t hash_size)
270f9159b7SSoby Mathew {
280f9159b7SSoby Mathew size_t leftover;
290f9159b7SSoby Mathew /*
300f9159b7SSoby Mathew * bytes_per_line is always a power of two, so it can be used to
310f9159b7SSoby Mathew * construct mask with it when it is necessary to count remainder.
320f9159b7SSoby Mathew *
330f9159b7SSoby Mathew */
340f9159b7SSoby Mathew const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE;
350f9159b7SSoby Mathew char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE +
360f9159b7SSoby Mathew LENGTH_OF_TERMINATING_ZERO_IN_BYTES];
370f9159b7SSoby Mathew const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
380f9159b7SSoby Mathew '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
390f9159b7SSoby Mathew unsigned int i;
400f9159b7SSoby Mathew
410f9159b7SSoby Mathew for (i = 0U; i < hash_size; ++i) {
420f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] =
430f9159b7SSoby Mathew hex_chars[hash[i] >> 4];
440f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] =
450f9159b7SSoby Mathew hex_chars[hash[i] & 0x0f];
460f9159b7SSoby Mathew if (((i + 1) & (bytes_per_line - 1)) == 0U) {
470f9159b7SSoby Mathew hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0';
480f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n",
490f9159b7SSoby Mathew (i >> BYTES_PER_LINE_BASE) + 1, hash_text);
500f9159b7SSoby Mathew }
510f9159b7SSoby Mathew }
520f9159b7SSoby Mathew
530f9159b7SSoby Mathew leftover = (size_t)i & (bytes_per_line - 1);
540f9159b7SSoby Mathew
550f9159b7SSoby Mathew if (leftover != 0UL) {
560f9159b7SSoby Mathew hash_text[leftover * DIGITS_PER_BYTE] = '\0';
570f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1,
580f9159b7SSoby Mathew hash_text);
590f9159b7SSoby Mathew }
600f9159b7SSoby Mathew }
610f9159b7SSoby Mathew
620f9159b7SSoby Mathew /*
63dc65ae46SJavier Almansa Sobrino * Helper function to validate that the buffer base and length are
64dc65ae46SJavier Almansa Sobrino * within range.
650f9159b7SSoby Mathew */
validate_buffer_params(uint64_t buf_pa,uint64_t buf_len)66dc65ae46SJavier Almansa Sobrino static int validate_buffer_params(uint64_t buf_pa, uint64_t buf_len)
670f9159b7SSoby Mathew {
68dc65ae46SJavier Almansa Sobrino unsigned long shared_buf_page;
69dc65ae46SJavier Almansa Sobrino uintptr_t shared_buf_base;
700f9159b7SSoby Mathew
71dc65ae46SJavier Almansa Sobrino (void)plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base);
720f9159b7SSoby Mathew
73dc65ae46SJavier Almansa Sobrino shared_buf_page = shared_buf_base & ~PAGE_SIZE_MASK;
74dc65ae46SJavier Almansa Sobrino
75dc65ae46SJavier Almansa Sobrino /* Validate the buffer pointer */
76dc65ae46SJavier Almansa Sobrino if ((buf_pa & ~PAGE_SIZE_MASK) != shared_buf_page) {
77dc65ae46SJavier Almansa Sobrino ERROR("Buffer PA out of range\n");
78dc65ae46SJavier Almansa Sobrino return E_RMM_BAD_ADDR;
790f9159b7SSoby Mathew }
800f9159b7SSoby Mathew
81dc65ae46SJavier Almansa Sobrino /* Validate the size of the shared area */
82dc65ae46SJavier Almansa Sobrino if (((buf_pa + buf_len - 1UL) & ~PAGE_SIZE_MASK) != shared_buf_page) {
83dc65ae46SJavier Almansa Sobrino ERROR("Invalid buffer length\n");
84dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL;
85dc65ae46SJavier Almansa Sobrino }
86dc65ae46SJavier Almansa Sobrino
87dc65ae46SJavier Almansa Sobrino return 0; /* No error */
88dc65ae46SJavier Almansa Sobrino }
89dc65ae46SJavier Almansa Sobrino
rmmd_attest_get_platform_token(uint64_t buf_pa,uint64_t * buf_size,uint64_t c_size,uint64_t * remaining_len)90dc65ae46SJavier Almansa Sobrino int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size,
9142cf6026SJuan Pablo Conde uint64_t c_size,
9242cf6026SJuan Pablo Conde uint64_t *remaining_len)
93dc65ae46SJavier Almansa Sobrino {
94dc65ae46SJavier Almansa Sobrino int err;
95dc65ae46SJavier Almansa Sobrino uint8_t temp_buf[SHA512_DIGEST_SIZE];
96dc65ae46SJavier Almansa Sobrino
97dc65ae46SJavier Almansa Sobrino err = validate_buffer_params(buf_pa, *buf_size);
98dc65ae46SJavier Almansa Sobrino if (err != 0) {
99dc65ae46SJavier Almansa Sobrino return err;
100dc65ae46SJavier Almansa Sobrino }
101dc65ae46SJavier Almansa Sobrino
102dc65ae46SJavier Almansa Sobrino if ((c_size != SHA256_DIGEST_SIZE) &&
103dc65ae46SJavier Almansa Sobrino (c_size != SHA384_DIGEST_SIZE) &&
104dc65ae46SJavier Almansa Sobrino (c_size != SHA512_DIGEST_SIZE)) {
105dc65ae46SJavier Almansa Sobrino ERROR("Invalid hash size: %lu\n", c_size);
106dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL;
1070f9159b7SSoby Mathew }
1080f9159b7SSoby Mathew
1090f9159b7SSoby Mathew spin_lock(&lock);
1100f9159b7SSoby Mathew
111dc65ae46SJavier Almansa Sobrino (void)memcpy(temp_buf, (void *)buf_pa, c_size);
1120f9159b7SSoby Mathew
113dc65ae46SJavier Almansa Sobrino print_challenge((uint8_t *)temp_buf, c_size);
1140f9159b7SSoby Mathew
1150f9159b7SSoby Mathew /* Get the platform token. */
116dc65ae46SJavier Almansa Sobrino err = plat_rmmd_get_cca_attest_token((uintptr_t)buf_pa,
11742cf6026SJuan Pablo Conde buf_size, (uintptr_t)temp_buf, c_size, remaining_len);
1180f9159b7SSoby Mathew
11942cf6026SJuan Pablo Conde switch (err) {
12042cf6026SJuan Pablo Conde case 0:
12142cf6026SJuan Pablo Conde err = E_RMM_OK;
12242cf6026SJuan Pablo Conde break;
12342cf6026SJuan Pablo Conde case -EAGAIN:
12442cf6026SJuan Pablo Conde err = E_RMM_AGAIN;
12542cf6026SJuan Pablo Conde break;
12642cf6026SJuan Pablo Conde case -EINVAL:
12742cf6026SJuan Pablo Conde err = E_RMM_INVAL;
12842cf6026SJuan Pablo Conde break;
12942cf6026SJuan Pablo Conde default:
1300f9159b7SSoby Mathew ERROR("Failed to get platform token: %d.\n", err);
131dc65ae46SJavier Almansa Sobrino err = E_RMM_UNK;
1320f9159b7SSoby Mathew }
1330f9159b7SSoby Mathew
1340f9159b7SSoby Mathew spin_unlock(&lock);
1350f9159b7SSoby Mathew
1360f9159b7SSoby Mathew return err;
1370f9159b7SSoby Mathew }
1380f9159b7SSoby Mathew
rmmd_attest_get_signing_key(uint64_t buf_pa,uint64_t * buf_size,uint64_t ecc_curve)139dc65ae46SJavier Almansa Sobrino int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size,
140a0435105SSoby Mathew uint64_t ecc_curve)
141a0435105SSoby Mathew {
142a0435105SSoby Mathew int err;
143a0435105SSoby Mathew
144dc65ae46SJavier Almansa Sobrino err = validate_buffer_params(buf_pa, *buf_size);
145dc65ae46SJavier Almansa Sobrino if (err != 0) {
146dc65ae46SJavier Almansa Sobrino return err;
147a0435105SSoby Mathew }
148a0435105SSoby Mathew
149a0435105SSoby Mathew if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
150a0435105SSoby Mathew ERROR("Invalid ECC curve specified\n");
151dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL;
152a0435105SSoby Mathew }
153a0435105SSoby Mathew
154a0435105SSoby Mathew spin_lock(&lock);
155a0435105SSoby Mathew
156a0435105SSoby Mathew /* Get the Realm attestation key. */
157dc65ae46SJavier Almansa Sobrino err = plat_rmmd_get_cca_realm_attest_key((uintptr_t)buf_pa, buf_size,
158dc65ae46SJavier Almansa Sobrino (unsigned int)ecc_curve);
159a0435105SSoby Mathew if (err != 0) {
160a0435105SSoby Mathew ERROR("Failed to get attestation key: %d.\n", err);
161dc65ae46SJavier Almansa Sobrino err = E_RMM_UNK;
162a0435105SSoby Mathew }
163a0435105SSoby Mathew
164a0435105SSoby Mathew spin_unlock(&lock);
165a0435105SSoby Mathew
166a0435105SSoby Mathew return err;
167a0435105SSoby Mathew }
168*6a88ec8bSRaghu Krishnamurthy
rmmd_el3_token_sign_push_req(uint64_t buf_pa,uint64_t buf_size)169*6a88ec8bSRaghu Krishnamurthy static int rmmd_el3_token_sign_push_req(uint64_t buf_pa, uint64_t buf_size)
170*6a88ec8bSRaghu Krishnamurthy {
171*6a88ec8bSRaghu Krishnamurthy int err;
172*6a88ec8bSRaghu Krishnamurthy
173*6a88ec8bSRaghu Krishnamurthy err = validate_buffer_params(buf_pa, buf_size);
174*6a88ec8bSRaghu Krishnamurthy if (err != 0) {
175*6a88ec8bSRaghu Krishnamurthy return err;
176*6a88ec8bSRaghu Krishnamurthy }
177*6a88ec8bSRaghu Krishnamurthy
178*6a88ec8bSRaghu Krishnamurthy if (buf_size < sizeof(struct el3_token_sign_request)) {
179*6a88ec8bSRaghu Krishnamurthy return E_RMM_INVAL;
180*6a88ec8bSRaghu Krishnamurthy }
181*6a88ec8bSRaghu Krishnamurthy
182*6a88ec8bSRaghu Krishnamurthy spin_lock(&lock);
183*6a88ec8bSRaghu Krishnamurthy
184*6a88ec8bSRaghu Krishnamurthy /* Call platform port to handle attestation toekn signing request. */
185*6a88ec8bSRaghu Krishnamurthy err = plat_rmmd_el3_token_sign_push_req((struct el3_token_sign_request *)buf_pa);
186*6a88ec8bSRaghu Krishnamurthy
187*6a88ec8bSRaghu Krishnamurthy spin_unlock(&lock);
188*6a88ec8bSRaghu Krishnamurthy
189*6a88ec8bSRaghu Krishnamurthy return err;
190*6a88ec8bSRaghu Krishnamurthy }
191*6a88ec8bSRaghu Krishnamurthy
rmmd_el3_token_sign_pull_resp(uint64_t buf_pa,uint64_t buf_size)192*6a88ec8bSRaghu Krishnamurthy static int rmmd_el3_token_sign_pull_resp(uint64_t buf_pa, uint64_t buf_size)
193*6a88ec8bSRaghu Krishnamurthy {
194*6a88ec8bSRaghu Krishnamurthy int err;
195*6a88ec8bSRaghu Krishnamurthy
196*6a88ec8bSRaghu Krishnamurthy err = validate_buffer_params(buf_pa, buf_size);
197*6a88ec8bSRaghu Krishnamurthy if (err != 0) {
198*6a88ec8bSRaghu Krishnamurthy return err;
199*6a88ec8bSRaghu Krishnamurthy }
200*6a88ec8bSRaghu Krishnamurthy
201*6a88ec8bSRaghu Krishnamurthy
202*6a88ec8bSRaghu Krishnamurthy if (buf_size < sizeof(struct el3_token_sign_response)) {
203*6a88ec8bSRaghu Krishnamurthy return E_RMM_INVAL;
204*6a88ec8bSRaghu Krishnamurthy }
205*6a88ec8bSRaghu Krishnamurthy
206*6a88ec8bSRaghu Krishnamurthy spin_lock(&lock);
207*6a88ec8bSRaghu Krishnamurthy
208*6a88ec8bSRaghu Krishnamurthy /* Pull attestation signing response from HES. */
209*6a88ec8bSRaghu Krishnamurthy err = plat_rmmd_el3_token_sign_pull_resp(
210*6a88ec8bSRaghu Krishnamurthy (struct el3_token_sign_response *)buf_pa);
211*6a88ec8bSRaghu Krishnamurthy
212*6a88ec8bSRaghu Krishnamurthy spin_unlock(&lock);
213*6a88ec8bSRaghu Krishnamurthy
214*6a88ec8bSRaghu Krishnamurthy return err;
215*6a88ec8bSRaghu Krishnamurthy }
216*6a88ec8bSRaghu Krishnamurthy
rmmd_attest_get_attest_pub_key(uint64_t buf_pa,uint64_t * buf_size,uint64_t ecc_curve)217*6a88ec8bSRaghu Krishnamurthy static int rmmd_attest_get_attest_pub_key(uint64_t buf_pa, uint64_t *buf_size,
218*6a88ec8bSRaghu Krishnamurthy uint64_t ecc_curve)
219*6a88ec8bSRaghu Krishnamurthy {
220*6a88ec8bSRaghu Krishnamurthy int err;
221*6a88ec8bSRaghu Krishnamurthy
222*6a88ec8bSRaghu Krishnamurthy err = validate_buffer_params(buf_pa, *buf_size);
223*6a88ec8bSRaghu Krishnamurthy if (err != 0) {
224*6a88ec8bSRaghu Krishnamurthy return err;
225*6a88ec8bSRaghu Krishnamurthy }
226*6a88ec8bSRaghu Krishnamurthy
227*6a88ec8bSRaghu Krishnamurthy if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
228*6a88ec8bSRaghu Krishnamurthy ERROR("Invalid ECC curve specified\n");
229*6a88ec8bSRaghu Krishnamurthy return E_RMM_INVAL;
230*6a88ec8bSRaghu Krishnamurthy }
231*6a88ec8bSRaghu Krishnamurthy
232*6a88ec8bSRaghu Krishnamurthy spin_lock(&lock);
233*6a88ec8bSRaghu Krishnamurthy
234*6a88ec8bSRaghu Krishnamurthy /* Get the Realm attestation public key from platform port. */
235*6a88ec8bSRaghu Krishnamurthy err = plat_rmmd_el3_token_sign_get_rak_pub(
236*6a88ec8bSRaghu Krishnamurthy (uintptr_t)buf_pa, buf_size, (unsigned int)ecc_curve);
237*6a88ec8bSRaghu Krishnamurthy
238*6a88ec8bSRaghu Krishnamurthy spin_unlock(&lock);
239*6a88ec8bSRaghu Krishnamurthy if (err != 0) {
240*6a88ec8bSRaghu Krishnamurthy ERROR("Failed to get attestation public key from HES: %d.\n",
241*6a88ec8bSRaghu Krishnamurthy err);
242*6a88ec8bSRaghu Krishnamurthy err = E_RMM_UNK;
243*6a88ec8bSRaghu Krishnamurthy }
244*6a88ec8bSRaghu Krishnamurthy
245*6a88ec8bSRaghu Krishnamurthy
246*6a88ec8bSRaghu Krishnamurthy return err;
247*6a88ec8bSRaghu Krishnamurthy }
248*6a88ec8bSRaghu Krishnamurthy
rmmd_el3_token_sign(void * handle,uint64_t opcode,uint64_t x2,uint64_t x3,uint64_t x4)249*6a88ec8bSRaghu Krishnamurthy uint64_t rmmd_el3_token_sign(void *handle, uint64_t opcode, uint64_t x2,
250*6a88ec8bSRaghu Krishnamurthy uint64_t x3, uint64_t x4)
251*6a88ec8bSRaghu Krishnamurthy {
252*6a88ec8bSRaghu Krishnamurthy int ret;
253*6a88ec8bSRaghu Krishnamurthy
254*6a88ec8bSRaghu Krishnamurthy switch (opcode) {
255*6a88ec8bSRaghu Krishnamurthy case RMM_EL3_TOKEN_SIGN_PUSH_REQ_OP:
256*6a88ec8bSRaghu Krishnamurthy ret = rmmd_el3_token_sign_push_req(x2, x3);
257*6a88ec8bSRaghu Krishnamurthy SMC_RET1(handle, ret);
258*6a88ec8bSRaghu Krishnamurthy case RMM_EL3_TOKEN_SIGN_PULL_RESP_OP:
259*6a88ec8bSRaghu Krishnamurthy ret = rmmd_el3_token_sign_pull_resp(x2, x3);
260*6a88ec8bSRaghu Krishnamurthy SMC_RET1(handle, ret);
261*6a88ec8bSRaghu Krishnamurthy case RMM_EL3_TOKEN_SIGN_GET_RAK_PUB_OP:
262*6a88ec8bSRaghu Krishnamurthy ret = rmmd_attest_get_attest_pub_key(x2, &x3, x4);
263*6a88ec8bSRaghu Krishnamurthy SMC_RET2(handle, ret, x3);
264*6a88ec8bSRaghu Krishnamurthy default:
265*6a88ec8bSRaghu Krishnamurthy SMC_RET1(handle, SMC_UNK);
266*6a88ec8bSRaghu Krishnamurthy }
267*6a88ec8bSRaghu Krishnamurthy }
268