10f9159b7SSoby Mathew /* 2*42cf6026SJuan Pablo Conde * Copyright (c) 2022-2024, Arm Limited. All rights reserved. 30f9159b7SSoby Mathew * 40f9159b7SSoby Mathew * SPDX-License-Identifier: BSD-3-Clause 50f9159b7SSoby Mathew */ 6*42cf6026SJuan Pablo Conde #include <errno.h> 70f9159b7SSoby Mathew #include <stdint.h> 80f9159b7SSoby Mathew #include <string.h> 91d0ca40eSJavier Almansa Sobrino 100f9159b7SSoby Mathew #include <common/debug.h> 110f9159b7SSoby Mathew #include <lib/spinlock.h> 120f9159b7SSoby Mathew #include <lib/xlat_tables/xlat_tables_v2.h> 130f9159b7SSoby Mathew #include <plat/common/platform.h> 140f9159b7SSoby Mathew #include "rmmd_private.h" 150f9159b7SSoby Mathew #include <services/rmmd_svc.h> 160f9159b7SSoby Mathew 170f9159b7SSoby Mathew static spinlock_t lock; 180f9159b7SSoby Mathew 190f9159b7SSoby Mathew /* For printing Realm attestation token hash */ 200f9159b7SSoby Mathew #define DIGITS_PER_BYTE 2UL 210f9159b7SSoby Mathew #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL 220f9159b7SSoby Mathew #define BYTES_PER_LINE_BASE 4UL 230f9159b7SSoby Mathew 240f9159b7SSoby Mathew static void print_challenge(uint8_t *hash, size_t hash_size) 250f9159b7SSoby Mathew { 260f9159b7SSoby Mathew size_t leftover; 270f9159b7SSoby Mathew /* 280f9159b7SSoby Mathew * bytes_per_line is always a power of two, so it can be used to 290f9159b7SSoby Mathew * construct mask with it when it is necessary to count remainder. 300f9159b7SSoby Mathew * 310f9159b7SSoby Mathew */ 320f9159b7SSoby Mathew const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE; 330f9159b7SSoby Mathew char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE + 340f9159b7SSoby Mathew LENGTH_OF_TERMINATING_ZERO_IN_BYTES]; 350f9159b7SSoby Mathew const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', 360f9159b7SSoby Mathew '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 370f9159b7SSoby Mathew unsigned int i; 380f9159b7SSoby Mathew 390f9159b7SSoby Mathew for (i = 0U; i < hash_size; ++i) { 400f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] = 410f9159b7SSoby Mathew hex_chars[hash[i] >> 4]; 420f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] = 430f9159b7SSoby Mathew hex_chars[hash[i] & 0x0f]; 440f9159b7SSoby Mathew if (((i + 1) & (bytes_per_line - 1)) == 0U) { 450f9159b7SSoby Mathew hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0'; 460f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n", 470f9159b7SSoby Mathew (i >> BYTES_PER_LINE_BASE) + 1, hash_text); 480f9159b7SSoby Mathew } 490f9159b7SSoby Mathew } 500f9159b7SSoby Mathew 510f9159b7SSoby Mathew leftover = (size_t)i & (bytes_per_line - 1); 520f9159b7SSoby Mathew 530f9159b7SSoby Mathew if (leftover != 0UL) { 540f9159b7SSoby Mathew hash_text[leftover * DIGITS_PER_BYTE] = '\0'; 550f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1, 560f9159b7SSoby Mathew hash_text); 570f9159b7SSoby Mathew } 580f9159b7SSoby Mathew } 590f9159b7SSoby Mathew 600f9159b7SSoby Mathew /* 61dc65ae46SJavier Almansa Sobrino * Helper function to validate that the buffer base and length are 62dc65ae46SJavier Almansa Sobrino * within range. 630f9159b7SSoby Mathew */ 64dc65ae46SJavier Almansa Sobrino static int validate_buffer_params(uint64_t buf_pa, uint64_t buf_len) 650f9159b7SSoby Mathew { 66dc65ae46SJavier Almansa Sobrino unsigned long shared_buf_page; 67dc65ae46SJavier Almansa Sobrino uintptr_t shared_buf_base; 680f9159b7SSoby Mathew 69dc65ae46SJavier Almansa Sobrino (void)plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base); 700f9159b7SSoby Mathew 71dc65ae46SJavier Almansa Sobrino shared_buf_page = shared_buf_base & ~PAGE_SIZE_MASK; 72dc65ae46SJavier Almansa Sobrino 73dc65ae46SJavier Almansa Sobrino /* Validate the buffer pointer */ 74dc65ae46SJavier Almansa Sobrino if ((buf_pa & ~PAGE_SIZE_MASK) != shared_buf_page) { 75dc65ae46SJavier Almansa Sobrino ERROR("Buffer PA out of range\n"); 76dc65ae46SJavier Almansa Sobrino return E_RMM_BAD_ADDR; 770f9159b7SSoby Mathew } 780f9159b7SSoby Mathew 79dc65ae46SJavier Almansa Sobrino /* Validate the size of the shared area */ 80dc65ae46SJavier Almansa Sobrino if (((buf_pa + buf_len - 1UL) & ~PAGE_SIZE_MASK) != shared_buf_page) { 81dc65ae46SJavier Almansa Sobrino ERROR("Invalid buffer length\n"); 82dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL; 83dc65ae46SJavier Almansa Sobrino } 84dc65ae46SJavier Almansa Sobrino 85dc65ae46SJavier Almansa Sobrino return 0; /* No error */ 86dc65ae46SJavier Almansa Sobrino } 87dc65ae46SJavier Almansa Sobrino 88dc65ae46SJavier Almansa Sobrino int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size, 89*42cf6026SJuan Pablo Conde uint64_t c_size, 90*42cf6026SJuan Pablo Conde uint64_t *remaining_len) 91dc65ae46SJavier Almansa Sobrino { 92dc65ae46SJavier Almansa Sobrino int err; 93dc65ae46SJavier Almansa Sobrino uint8_t temp_buf[SHA512_DIGEST_SIZE]; 94dc65ae46SJavier Almansa Sobrino 95dc65ae46SJavier Almansa Sobrino err = validate_buffer_params(buf_pa, *buf_size); 96dc65ae46SJavier Almansa Sobrino if (err != 0) { 97dc65ae46SJavier Almansa Sobrino return err; 98dc65ae46SJavier Almansa Sobrino } 99dc65ae46SJavier Almansa Sobrino 100dc65ae46SJavier Almansa Sobrino if ((c_size != SHA256_DIGEST_SIZE) && 101dc65ae46SJavier Almansa Sobrino (c_size != SHA384_DIGEST_SIZE) && 102dc65ae46SJavier Almansa Sobrino (c_size != SHA512_DIGEST_SIZE)) { 103dc65ae46SJavier Almansa Sobrino ERROR("Invalid hash size: %lu\n", c_size); 104dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL; 1050f9159b7SSoby Mathew } 1060f9159b7SSoby Mathew 1070f9159b7SSoby Mathew spin_lock(&lock); 1080f9159b7SSoby Mathew 109dc65ae46SJavier Almansa Sobrino (void)memcpy(temp_buf, (void *)buf_pa, c_size); 1100f9159b7SSoby Mathew 111dc65ae46SJavier Almansa Sobrino print_challenge((uint8_t *)temp_buf, c_size); 1120f9159b7SSoby Mathew 1130f9159b7SSoby Mathew /* Get the platform token. */ 114dc65ae46SJavier Almansa Sobrino err = plat_rmmd_get_cca_attest_token((uintptr_t)buf_pa, 115*42cf6026SJuan Pablo Conde buf_size, (uintptr_t)temp_buf, c_size, remaining_len); 1160f9159b7SSoby Mathew 117*42cf6026SJuan Pablo Conde switch (err) { 118*42cf6026SJuan Pablo Conde case 0: 119*42cf6026SJuan Pablo Conde err = E_RMM_OK; 120*42cf6026SJuan Pablo Conde break; 121*42cf6026SJuan Pablo Conde case -EAGAIN: 122*42cf6026SJuan Pablo Conde err = E_RMM_AGAIN; 123*42cf6026SJuan Pablo Conde break; 124*42cf6026SJuan Pablo Conde case -EINVAL: 125*42cf6026SJuan Pablo Conde err = E_RMM_INVAL; 126*42cf6026SJuan Pablo Conde break; 127*42cf6026SJuan Pablo Conde default: 1280f9159b7SSoby Mathew ERROR("Failed to get platform token: %d.\n", err); 129dc65ae46SJavier Almansa Sobrino err = E_RMM_UNK; 1300f9159b7SSoby Mathew } 1310f9159b7SSoby Mathew 1320f9159b7SSoby Mathew spin_unlock(&lock); 1330f9159b7SSoby Mathew 1340f9159b7SSoby Mathew return err; 1350f9159b7SSoby Mathew } 1360f9159b7SSoby Mathew 137dc65ae46SJavier Almansa Sobrino int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size, 138a0435105SSoby Mathew uint64_t ecc_curve) 139a0435105SSoby Mathew { 140a0435105SSoby Mathew int err; 141a0435105SSoby Mathew 142dc65ae46SJavier Almansa Sobrino err = validate_buffer_params(buf_pa, *buf_size); 143dc65ae46SJavier Almansa Sobrino if (err != 0) { 144dc65ae46SJavier Almansa Sobrino return err; 145a0435105SSoby Mathew } 146a0435105SSoby Mathew 147a0435105SSoby Mathew if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) { 148a0435105SSoby Mathew ERROR("Invalid ECC curve specified\n"); 149dc65ae46SJavier Almansa Sobrino return E_RMM_INVAL; 150a0435105SSoby Mathew } 151a0435105SSoby Mathew 152a0435105SSoby Mathew spin_lock(&lock); 153a0435105SSoby Mathew 154a0435105SSoby Mathew /* Get the Realm attestation key. */ 155dc65ae46SJavier Almansa Sobrino err = plat_rmmd_get_cca_realm_attest_key((uintptr_t)buf_pa, buf_size, 156dc65ae46SJavier Almansa Sobrino (unsigned int)ecc_curve); 157a0435105SSoby Mathew if (err != 0) { 158a0435105SSoby Mathew ERROR("Failed to get attestation key: %d.\n", err); 159dc65ae46SJavier Almansa Sobrino err = E_RMM_UNK; 160a0435105SSoby Mathew } 161a0435105SSoby Mathew 162a0435105SSoby Mathew spin_unlock(&lock); 163a0435105SSoby Mathew 164a0435105SSoby Mathew return err; 165a0435105SSoby Mathew } 166