1 /* 2 * Copyright (c) 2022-2024, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 #include <errno.h> 7 #include <stdint.h> 8 #include <string.h> 9 10 #include <common/debug.h> 11 #include <lib/spinlock.h> 12 #include <lib/xlat_tables/xlat_tables_v2.h> 13 #include <plat/common/platform.h> 14 #include "rmmd_private.h" 15 #include <services/rmmd_svc.h> 16 17 static spinlock_t lock; 18 19 /* For printing Realm attestation token hash */ 20 #define DIGITS_PER_BYTE 2UL 21 #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL 22 #define BYTES_PER_LINE_BASE 4UL 23 24 static void print_challenge(uint8_t *hash, size_t hash_size) 25 { 26 size_t leftover; 27 /* 28 * bytes_per_line is always a power of two, so it can be used to 29 * construct mask with it when it is necessary to count remainder. 30 * 31 */ 32 const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE; 33 char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE + 34 LENGTH_OF_TERMINATING_ZERO_IN_BYTES]; 35 const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', 36 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 37 unsigned int i; 38 39 for (i = 0U; i < hash_size; ++i) { 40 hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] = 41 hex_chars[hash[i] >> 4]; 42 hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] = 43 hex_chars[hash[i] & 0x0f]; 44 if (((i + 1) & (bytes_per_line - 1)) == 0U) { 45 hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0'; 46 VERBOSE("hash part %u = %s\n", 47 (i >> BYTES_PER_LINE_BASE) + 1, hash_text); 48 } 49 } 50 51 leftover = (size_t)i & (bytes_per_line - 1); 52 53 if (leftover != 0UL) { 54 hash_text[leftover * DIGITS_PER_BYTE] = '\0'; 55 VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1, 56 hash_text); 57 } 58 } 59 60 /* 61 * Helper function to validate that the buffer base and length are 62 * within range. 63 */ 64 static int validate_buffer_params(uint64_t buf_pa, uint64_t buf_len) 65 { 66 unsigned long shared_buf_page; 67 uintptr_t shared_buf_base; 68 69 (void)plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base); 70 71 shared_buf_page = shared_buf_base & ~PAGE_SIZE_MASK; 72 73 /* Validate the buffer pointer */ 74 if ((buf_pa & ~PAGE_SIZE_MASK) != shared_buf_page) { 75 ERROR("Buffer PA out of range\n"); 76 return E_RMM_BAD_ADDR; 77 } 78 79 /* Validate the size of the shared area */ 80 if (((buf_pa + buf_len - 1UL) & ~PAGE_SIZE_MASK) != shared_buf_page) { 81 ERROR("Invalid buffer length\n"); 82 return E_RMM_INVAL; 83 } 84 85 return 0; /* No error */ 86 } 87 88 int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size, 89 uint64_t c_size, 90 uint64_t *remaining_len) 91 { 92 int err; 93 uint8_t temp_buf[SHA512_DIGEST_SIZE]; 94 95 err = validate_buffer_params(buf_pa, *buf_size); 96 if (err != 0) { 97 return err; 98 } 99 100 if ((c_size != SHA256_DIGEST_SIZE) && 101 (c_size != SHA384_DIGEST_SIZE) && 102 (c_size != SHA512_DIGEST_SIZE)) { 103 ERROR("Invalid hash size: %lu\n", c_size); 104 return E_RMM_INVAL; 105 } 106 107 spin_lock(&lock); 108 109 (void)memcpy(temp_buf, (void *)buf_pa, c_size); 110 111 print_challenge((uint8_t *)temp_buf, c_size); 112 113 /* Get the platform token. */ 114 err = plat_rmmd_get_cca_attest_token((uintptr_t)buf_pa, 115 buf_size, (uintptr_t)temp_buf, c_size, remaining_len); 116 117 switch (err) { 118 case 0: 119 err = E_RMM_OK; 120 break; 121 case -EAGAIN: 122 err = E_RMM_AGAIN; 123 break; 124 case -EINVAL: 125 err = E_RMM_INVAL; 126 break; 127 default: 128 ERROR("Failed to get platform token: %d.\n", err); 129 err = E_RMM_UNK; 130 } 131 132 spin_unlock(&lock); 133 134 return err; 135 } 136 137 int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size, 138 uint64_t ecc_curve) 139 { 140 int err; 141 142 err = validate_buffer_params(buf_pa, *buf_size); 143 if (err != 0) { 144 return err; 145 } 146 147 if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) { 148 ERROR("Invalid ECC curve specified\n"); 149 return E_RMM_INVAL; 150 } 151 152 spin_lock(&lock); 153 154 /* Get the Realm attestation key. */ 155 err = plat_rmmd_get_cca_realm_attest_key((uintptr_t)buf_pa, buf_size, 156 (unsigned int)ecc_curve); 157 if (err != 0) { 158 ERROR("Failed to get attestation key: %d.\n", err); 159 err = E_RMM_UNK; 160 } 161 162 spin_unlock(&lock); 163 164 return err; 165 } 166