xref: /rk3399_ARM-atf/services/std_svc/rmmd/rmmd_attest.c (revision a0435105f229a65c7861b5997793f905cf90b823)
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