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