10f9159b7SSoby Mathew /* 20f9159b7SSoby Mathew * Copyright (c) 2022, Arm Limited. All rights reserved. 30f9159b7SSoby Mathew * 40f9159b7SSoby Mathew * SPDX-License-Identifier: BSD-3-Clause 50f9159b7SSoby Mathew */ 60f9159b7SSoby Mathew #include <stdint.h> 70f9159b7SSoby Mathew #include <string.h> 80f9159b7SSoby Mathew #include <common/debug.h> 90f9159b7SSoby Mathew #include <lib/spinlock.h> 100f9159b7SSoby Mathew #include <lib/xlat_tables/xlat_tables_v2.h> 110f9159b7SSoby Mathew #include <plat/common/platform.h> 120f9159b7SSoby Mathew #include "rmmd_private.h" 130f9159b7SSoby Mathew #include <services/rmmd_svc.h> 140f9159b7SSoby Mathew 150f9159b7SSoby Mathew static spinlock_t lock; 160f9159b7SSoby Mathew 170f9159b7SSoby Mathew /* For printing Realm attestation token hash */ 180f9159b7SSoby Mathew #define DIGITS_PER_BYTE 2UL 190f9159b7SSoby Mathew #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL 200f9159b7SSoby Mathew #define BYTES_PER_LINE_BASE 4UL 210f9159b7SSoby Mathew 220f9159b7SSoby Mathew static void print_challenge(uint8_t *hash, size_t hash_size) 230f9159b7SSoby Mathew { 240f9159b7SSoby Mathew size_t leftover; 250f9159b7SSoby Mathew /* 260f9159b7SSoby Mathew * bytes_per_line is always a power of two, so it can be used to 270f9159b7SSoby Mathew * construct mask with it when it is necessary to count remainder. 280f9159b7SSoby Mathew * 290f9159b7SSoby Mathew */ 300f9159b7SSoby Mathew const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE; 310f9159b7SSoby Mathew char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE + 320f9159b7SSoby Mathew LENGTH_OF_TERMINATING_ZERO_IN_BYTES]; 330f9159b7SSoby Mathew const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', 340f9159b7SSoby Mathew '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 350f9159b7SSoby Mathew unsigned int i; 360f9159b7SSoby Mathew 370f9159b7SSoby Mathew for (i = 0U; i < hash_size; ++i) { 380f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] = 390f9159b7SSoby Mathew hex_chars[hash[i] >> 4]; 400f9159b7SSoby Mathew hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] = 410f9159b7SSoby Mathew hex_chars[hash[i] & 0x0f]; 420f9159b7SSoby Mathew if (((i + 1) & (bytes_per_line - 1)) == 0U) { 430f9159b7SSoby Mathew hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0'; 440f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n", 450f9159b7SSoby Mathew (i >> BYTES_PER_LINE_BASE) + 1, hash_text); 460f9159b7SSoby Mathew } 470f9159b7SSoby Mathew } 480f9159b7SSoby Mathew 490f9159b7SSoby Mathew leftover = (size_t)i & (bytes_per_line - 1); 500f9159b7SSoby Mathew 510f9159b7SSoby Mathew if (leftover != 0UL) { 520f9159b7SSoby Mathew hash_text[leftover * DIGITS_PER_BYTE] = '\0'; 530f9159b7SSoby Mathew VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1, 540f9159b7SSoby Mathew hash_text); 550f9159b7SSoby Mathew } 560f9159b7SSoby Mathew } 570f9159b7SSoby Mathew 580f9159b7SSoby Mathew /* 590f9159b7SSoby Mathew * TODO: Have different error codes for different errors so that the caller can 600f9159b7SSoby Mathew * differentiate various error cases. 610f9159b7SSoby Mathew */ 620f9159b7SSoby Mathew int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_len, uint64_t challenge_hash_len) 630f9159b7SSoby Mathew { 640f9159b7SSoby Mathew int err; 650f9159b7SSoby Mathew uintptr_t va; 660f9159b7SSoby Mathew uint8_t temp_buf[SHA512_DIGEST_SIZE]; 670f9159b7SSoby Mathew 680f9159b7SSoby Mathew /* 690f9159b7SSoby Mathew * TODO: Currently we don't validate incoming buf_pa. This is a 700f9159b7SSoby Mathew * prototype and we will need to allocate static buffer for EL3-RMM 710f9159b7SSoby Mathew * communication. 720f9159b7SSoby Mathew */ 730f9159b7SSoby Mathew 740f9159b7SSoby Mathew /* We need a page of buffer to pass data */ 750f9159b7SSoby Mathew if (*buf_len != PAGE_SIZE) { 760f9159b7SSoby Mathew ERROR("Invalid buffer length\n"); 770f9159b7SSoby Mathew return RMMD_ERR_INVAL; 780f9159b7SSoby Mathew } 790f9159b7SSoby Mathew 800f9159b7SSoby Mathew if ((challenge_hash_len != SHA256_DIGEST_SIZE) && 810f9159b7SSoby Mathew (challenge_hash_len != SHA384_DIGEST_SIZE) && 820f9159b7SSoby Mathew (challenge_hash_len != SHA512_DIGEST_SIZE)) { 830f9159b7SSoby Mathew ERROR("Invalid hash size: %lu\n", challenge_hash_len); 840f9159b7SSoby Mathew return RMMD_ERR_INVAL; 850f9159b7SSoby Mathew } 860f9159b7SSoby Mathew 870f9159b7SSoby Mathew spin_lock(&lock); 880f9159b7SSoby Mathew 890f9159b7SSoby Mathew /* Map the buffer that was provided by the RMM. */ 900f9159b7SSoby Mathew err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE, 910f9159b7SSoby Mathew MT_RW_DATA | MT_REALM); 920f9159b7SSoby Mathew if (err != 0) { 930f9159b7SSoby Mathew ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n" 940f9159b7SSoby Mathew , err, (void *)buf_pa); 950f9159b7SSoby Mathew spin_unlock(&lock); 960f9159b7SSoby Mathew return RMMD_ERR_NOMEM; 970f9159b7SSoby Mathew } 980f9159b7SSoby Mathew 990f9159b7SSoby Mathew (void)memcpy(temp_buf, (void *)va, challenge_hash_len); 1000f9159b7SSoby Mathew 1010f9159b7SSoby Mathew print_challenge((uint8_t *)temp_buf, challenge_hash_len); 1020f9159b7SSoby Mathew 1030f9159b7SSoby Mathew /* Get the platform token. */ 1040f9159b7SSoby Mathew err = plat_get_cca_attest_token(va, 1050f9159b7SSoby Mathew buf_len, (uintptr_t)temp_buf, challenge_hash_len); 1060f9159b7SSoby Mathew 1070f9159b7SSoby Mathew if (err != 0) { 1080f9159b7SSoby Mathew ERROR("Failed to get platform token: %d.\n", err); 1090f9159b7SSoby Mathew err = RMMD_ERR_UNK; 1100f9159b7SSoby Mathew } 1110f9159b7SSoby Mathew 1120f9159b7SSoby Mathew /* Unmap RMM memory. */ 1130f9159b7SSoby Mathew (void)mmap_remove_dynamic_region(va, PAGE_SIZE); 1140f9159b7SSoby Mathew spin_unlock(&lock); 1150f9159b7SSoby Mathew 1160f9159b7SSoby Mathew return err; 1170f9159b7SSoby Mathew } 1180f9159b7SSoby Mathew 119*a0435105SSoby Mathew int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_len, 120*a0435105SSoby Mathew uint64_t ecc_curve) 121*a0435105SSoby Mathew { 122*a0435105SSoby Mathew int err; 123*a0435105SSoby Mathew uintptr_t va; 124*a0435105SSoby Mathew 125*a0435105SSoby Mathew /* 126*a0435105SSoby Mathew * TODO: Currently we don't validate incoming buf_pa. This is a 127*a0435105SSoby Mathew * prototype and we will need to allocate static buffer for EL3-RMM 128*a0435105SSoby Mathew * communication. 129*a0435105SSoby Mathew */ 130*a0435105SSoby Mathew 131*a0435105SSoby Mathew /* We need a page of buffer to pass data */ 132*a0435105SSoby Mathew if (*buf_len != PAGE_SIZE) { 133*a0435105SSoby Mathew ERROR("Invalid buffer length\n"); 134*a0435105SSoby Mathew return RMMD_ERR_INVAL; 135*a0435105SSoby Mathew } 136*a0435105SSoby Mathew 137*a0435105SSoby Mathew if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) { 138*a0435105SSoby Mathew ERROR("Invalid ECC curve specified\n"); 139*a0435105SSoby Mathew return RMMD_ERR_INVAL; 140*a0435105SSoby Mathew } 141*a0435105SSoby Mathew 142*a0435105SSoby Mathew spin_lock(&lock); 143*a0435105SSoby Mathew 144*a0435105SSoby Mathew /* Map the buffer that was provided by the RMM. */ 145*a0435105SSoby Mathew err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE, 146*a0435105SSoby Mathew MT_RW_DATA | MT_REALM); 147*a0435105SSoby Mathew if (err != 0) { 148*a0435105SSoby Mathew ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n" 149*a0435105SSoby Mathew , err, (void *)buf_pa); 150*a0435105SSoby Mathew spin_unlock(&lock); 151*a0435105SSoby Mathew return RMMD_ERR_NOMEM; 152*a0435105SSoby Mathew } 153*a0435105SSoby Mathew 154*a0435105SSoby Mathew /* Get the Realm attestation key. */ 155*a0435105SSoby Mathew err = plat_get_cca_realm_attest_key(va, buf_len, (unsigned int)ecc_curve); 156*a0435105SSoby Mathew if (err != 0) { 157*a0435105SSoby Mathew ERROR("Failed to get attestation key: %d.\n", err); 158*a0435105SSoby Mathew err = RMMD_ERR_UNK; 159*a0435105SSoby Mathew } 160*a0435105SSoby Mathew 161*a0435105SSoby Mathew /* Unmap RMM memory. */ 162*a0435105SSoby Mathew (void)mmap_remove_dynamic_region(va, PAGE_SIZE); 163*a0435105SSoby Mathew spin_unlock(&lock); 164*a0435105SSoby Mathew 165*a0435105SSoby Mathew return err; 166*a0435105SSoby Mathew } 167