/* * Copyright (c) 2022, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "rmmd_private.h" #include static spinlock_t lock; /* For printing Realm attestation token hash */ #define DIGITS_PER_BYTE 2UL #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES 1UL #define BYTES_PER_LINE_BASE 4UL static void print_challenge(uint8_t *hash, size_t hash_size) { size_t leftover; /* * bytes_per_line is always a power of two, so it can be used to * construct mask with it when it is necessary to count remainder. * */ const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE; char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE + LENGTH_OF_TERMINATING_ZERO_IN_BYTES]; const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; unsigned int i; for (i = 0U; i < hash_size; ++i) { hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] = hex_chars[hash[i] >> 4]; hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] = hex_chars[hash[i] & 0x0f]; if (((i + 1) & (bytes_per_line - 1)) == 0U) { hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0'; VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1, hash_text); } } leftover = (size_t)i & (bytes_per_line - 1); if (leftover != 0UL) { hash_text[leftover * DIGITS_PER_BYTE] = '\0'; VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1, hash_text); } } /* * TODO: Have different error codes for different errors so that the caller can * differentiate various error cases. */ int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_len, uint64_t challenge_hash_len) { int err; uintptr_t va; uint8_t temp_buf[SHA512_DIGEST_SIZE]; /* * TODO: Currently we don't validate incoming buf_pa. This is a * prototype and we will need to allocate static buffer for EL3-RMM * communication. */ /* We need a page of buffer to pass data */ if (*buf_len != PAGE_SIZE) { ERROR("Invalid buffer length\n"); return RMMD_ERR_INVAL; } if ((challenge_hash_len != SHA256_DIGEST_SIZE) && (challenge_hash_len != SHA384_DIGEST_SIZE) && (challenge_hash_len != SHA512_DIGEST_SIZE)) { ERROR("Invalid hash size: %lu\n", challenge_hash_len); return RMMD_ERR_INVAL; } spin_lock(&lock); /* Map the buffer that was provided by the RMM. */ err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE, MT_RW_DATA | MT_REALM); if (err != 0) { ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n" , err, (void *)buf_pa); spin_unlock(&lock); return RMMD_ERR_NOMEM; } (void)memcpy(temp_buf, (void *)va, challenge_hash_len); print_challenge((uint8_t *)temp_buf, challenge_hash_len); /* Get the platform token. */ err = plat_get_cca_attest_token(va, buf_len, (uintptr_t)temp_buf, challenge_hash_len); if (err != 0) { ERROR("Failed to get platform token: %d.\n", err); err = RMMD_ERR_UNK; } /* Unmap RMM memory. */ (void)mmap_remove_dynamic_region(va, PAGE_SIZE); spin_unlock(&lock); return err; } int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_len, uint64_t ecc_curve) { int err; uintptr_t va; /* * TODO: Currently we don't validate incoming buf_pa. This is a * prototype and we will need to allocate static buffer for EL3-RMM * communication. */ /* We need a page of buffer to pass data */ if (*buf_len != PAGE_SIZE) { ERROR("Invalid buffer length\n"); return RMMD_ERR_INVAL; } if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) { ERROR("Invalid ECC curve specified\n"); return RMMD_ERR_INVAL; } spin_lock(&lock); /* Map the buffer that was provided by the RMM. */ err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE, MT_RW_DATA | MT_REALM); if (err != 0) { ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n" , err, (void *)buf_pa); spin_unlock(&lock); return RMMD_ERR_NOMEM; } /* Get the Realm attestation key. */ err = plat_get_cca_realm_attest_key(va, buf_len, (unsigned int)ecc_curve); if (err != 0) { ERROR("Failed to get attestation key: %d.\n", err); err = RMMD_ERR_UNK; } /* Unmap RMM memory. */ (void)mmap_remove_dynamic_region(va, PAGE_SIZE); spin_unlock(&lock); return err; }