xref: /rk3399_ARM-atf/services/std_svc/rmmd/rmmd_attest.c (revision f713e5954e0906443cd20ae97e229ddbb9ab7005)
1 /*
2  * Copyright (c) 2022, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <stdint.h>
7 #include <string.h>
8 #include <common/debug.h>
9 #include <lib/spinlock.h>
10 #include <lib/xlat_tables/xlat_tables_v2.h>
11 #include <plat/common/platform.h>
12 #include "rmmd_private.h"
13 #include <services/rmmd_svc.h>
14 
15 static spinlock_t lock;
16 
17 /* For printing Realm attestation token hash */
18 #define DIGITS_PER_BYTE				2UL
19 #define LENGTH_OF_TERMINATING_ZERO_IN_BYTES	1UL
20 #define BYTES_PER_LINE_BASE			4UL
21 
22 static void print_challenge(uint8_t *hash, size_t hash_size)
23 {
24 	size_t leftover;
25 	/*
26 	 * bytes_per_line is always a power of two, so it can be used to
27 	 * construct mask with it when it is necessary to count remainder.
28 	 *
29 	 */
30 	const size_t bytes_per_line = 1 << BYTES_PER_LINE_BASE;
31 	char hash_text[(1 << BYTES_PER_LINE_BASE) * DIGITS_PER_BYTE +
32 		LENGTH_OF_TERMINATING_ZERO_IN_BYTES];
33 	const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
34 				  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
35 	unsigned int i;
36 
37 	for (i = 0U; i < hash_size; ++i) {
38 		hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE] =
39 			hex_chars[hash[i] >> 4];
40 		hash_text[(i & (bytes_per_line - 1)) * DIGITS_PER_BYTE + 1] =
41 			hex_chars[hash[i] & 0x0f];
42 		if (((i + 1) & (bytes_per_line - 1)) == 0U) {
43 			hash_text[bytes_per_line * DIGITS_PER_BYTE] = '\0';
44 			VERBOSE("hash part %u = %s\n",
45 				(i >> BYTES_PER_LINE_BASE) + 1, hash_text);
46 		}
47 	}
48 
49 	leftover = (size_t)i & (bytes_per_line - 1);
50 
51 	if (leftover != 0UL) {
52 		hash_text[leftover * DIGITS_PER_BYTE] = '\0';
53 		VERBOSE("hash part %u = %s\n", (i >> BYTES_PER_LINE_BASE) + 1,
54 			hash_text);
55 	}
56 }
57 
58 /*
59  * TODO: Have different error codes for different errors so that the caller can
60  * differentiate various error cases.
61  */
62 int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_len, uint64_t challenge_hash_len)
63 {
64 	int err;
65 	uintptr_t va;
66 	uint8_t temp_buf[SHA512_DIGEST_SIZE];
67 
68 	/*
69 	 * TODO: Currently we don't validate incoming buf_pa. This is a
70 	 * prototype and we will need to allocate static buffer for EL3-RMM
71 	 * communication.
72 	 */
73 
74 	/* We need a page of buffer to pass data */
75 	if (*buf_len != PAGE_SIZE) {
76 		ERROR("Invalid buffer length\n");
77 		return RMMD_ERR_INVAL;
78 	}
79 
80 	if ((challenge_hash_len != SHA256_DIGEST_SIZE) &&
81 	    (challenge_hash_len != SHA384_DIGEST_SIZE) &&
82 	    (challenge_hash_len != SHA512_DIGEST_SIZE)) {
83 		ERROR("Invalid hash size: %lu\n", challenge_hash_len);
84 		return RMMD_ERR_INVAL;
85 	}
86 
87 	spin_lock(&lock);
88 
89 	/* Map the buffer that was provided by the RMM. */
90 	err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE,
91 					       MT_RW_DATA | MT_REALM);
92 	if (err != 0) {
93 		ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n"
94 		      , err, (void *)buf_pa);
95 		spin_unlock(&lock);
96 		return RMMD_ERR_NOMEM;
97 	}
98 
99 	(void)memcpy(temp_buf, (void *)va, challenge_hash_len);
100 
101 	print_challenge((uint8_t *)temp_buf, challenge_hash_len);
102 
103 	/* Get the platform token. */
104 	err = plat_get_cca_attest_token(va,
105 		buf_len, (uintptr_t)temp_buf, challenge_hash_len);
106 
107 	if (err != 0) {
108 		ERROR("Failed to get platform token: %d.\n", err);
109 		err = RMMD_ERR_UNK;
110 	}
111 
112 	/* Unmap RMM memory. */
113 	(void)mmap_remove_dynamic_region(va, PAGE_SIZE);
114 	spin_unlock(&lock);
115 
116 	return err;
117 }
118 
119 int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_len,
120 				uint64_t ecc_curve)
121 {
122 	int err;
123 	uintptr_t va;
124 
125 	/*
126 	 * TODO: Currently we don't validate incoming buf_pa. This is a
127 	 * prototype and we will need to allocate static buffer for EL3-RMM
128 	 * communication.
129 	 */
130 
131 	/* We need a page of buffer to pass data */
132 	if (*buf_len != PAGE_SIZE) {
133 		ERROR("Invalid buffer length\n");
134 		return RMMD_ERR_INVAL;
135 	}
136 
137 	if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
138 		ERROR("Invalid ECC curve specified\n");
139 		return RMMD_ERR_INVAL;
140 	}
141 
142 	spin_lock(&lock);
143 
144 	/* Map the buffer that was provided by the RMM. */
145 	err = mmap_add_dynamic_region_alloc_va(buf_pa, &va, PAGE_SIZE,
146 					       MT_RW_DATA | MT_REALM);
147 	if (err != 0) {
148 		ERROR("mmap_add_dynamic_region_alloc_va failed: %d (%p).\n"
149 		      , err, (void *)buf_pa);
150 		spin_unlock(&lock);
151 		return RMMD_ERR_NOMEM;
152 	}
153 
154 	/* Get the Realm attestation key. */
155 	err = plat_get_cca_realm_attest_key(va, buf_len, (unsigned int)ecc_curve);
156 	if (err != 0) {
157 		ERROR("Failed to get attestation key: %d.\n", err);
158 		err =  RMMD_ERR_UNK;
159 	}
160 
161 	/* Unmap RMM memory. */
162 	(void)mmap_remove_dynamic_region(va, PAGE_SIZE);
163 	spin_unlock(&lock);
164 
165 	return err;
166 }
167