summaryrefslogtreecommitdiffstats
path: root/services/std_svc/rmmd/rmmd_attest.c
blob: 25adf502f40edc2740d6ac0f853783a71365113f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright (c) 2022, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include <stdint.h>
#include <string.h>

#include <common/debug.h>
#include <lib/spinlock.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
#include "rmmd_private.h"
#include <services/rmmd_svc.h>

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);
	}
}

/*
 * Helper function to validate that the buffer base and length are
 * within range.
 */
static int validate_buffer_params(uint64_t buf_pa, uint64_t buf_len)
{
	unsigned long shared_buf_page;
	uintptr_t shared_buf_base;

	(void)plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base);

	shared_buf_page = shared_buf_base & ~PAGE_SIZE_MASK;

	/* Validate the buffer pointer */
	if ((buf_pa & ~PAGE_SIZE_MASK) != shared_buf_page) {
		ERROR("Buffer PA out of range\n");
		return E_RMM_BAD_ADDR;
	}

	/* Validate the size of the shared area */
	if (((buf_pa + buf_len - 1UL) & ~PAGE_SIZE_MASK) != shared_buf_page) {
		ERROR("Invalid buffer length\n");
		return E_RMM_INVAL;
	}

	return 0; /* No error */
}

int rmmd_attest_get_platform_token(uint64_t buf_pa, uint64_t *buf_size,
				   uint64_t c_size)
{
	int err;
	uint8_t temp_buf[SHA512_DIGEST_SIZE];

	err = validate_buffer_params(buf_pa, *buf_size);
	if (err != 0) {
		return err;
	}

	if ((c_size != SHA256_DIGEST_SIZE) &&
	    (c_size != SHA384_DIGEST_SIZE) &&
	    (c_size != SHA512_DIGEST_SIZE)) {
		ERROR("Invalid hash size: %lu\n", c_size);
		return E_RMM_INVAL;
	}

	spin_lock(&lock);

	(void)memcpy(temp_buf, (void *)buf_pa, c_size);

	print_challenge((uint8_t *)temp_buf, c_size);

	/* Get the platform token. */
	err = plat_rmmd_get_cca_attest_token((uintptr_t)buf_pa,
		buf_size, (uintptr_t)temp_buf, c_size);

	if (err != 0) {
		ERROR("Failed to get platform token: %d.\n", err);
		err = E_RMM_UNK;
	}

	spin_unlock(&lock);

	return err;
}

int rmmd_attest_get_signing_key(uint64_t buf_pa, uint64_t *buf_size,
				uint64_t ecc_curve)
{
	int err;

	err = validate_buffer_params(buf_pa, *buf_size);
	if (err != 0) {
		return err;
	}

	if (ecc_curve != ATTEST_KEY_CURVE_ECC_SECP384R1) {
		ERROR("Invalid ECC curve specified\n");
		return E_RMM_INVAL;
	}

	spin_lock(&lock);

	/* Get the Realm attestation key. */
	err = plat_rmmd_get_cca_realm_attest_key((uintptr_t)buf_pa, buf_size,
						 (unsigned int)ecc_curve);
	if (err != 0) {
		ERROR("Failed to get attestation key: %d.\n", err);
		err =  E_RMM_UNK;
	}

	spin_unlock(&lock);

	return err;
}