summaryrefslogtreecommitdiffstats
path: root/src/soc/amd/common/psp_verstage/vboot_crypto.c
blob: 89a4ccea5133ffb1647d6be6b0f4af3cf55a7a36 (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
/* SPDX-License-Identifier: GPL-2.0-only */

#include <2crypto.h>
#include <2return_codes.h>
#include <bl_uapp/bl_syscall_public.h>
#include <commonlib/bsd/helpers.h>
#include <console/console.h>
#include "psp_verstage.h"
#include <stddef.h>
#include <string.h>
#include <swab.h>
#include <vb2_api.h>

static struct sha_generic_data sha_op;
static uint32_t sha_op_size_remaining;
static uint8_t __attribute__((aligned(32))) sha_hash[64];

vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg, uint32_t data_size)
{
	printk(BIOS_DEBUG, "Calculating hash of %d bytes\n", data_size);

	sha_op_size_remaining = data_size;

	if (platform_set_sha_op(hash_alg, &sha_op) != 0) {
		printk(BIOS_INFO, "Unsupported hash_alg %d!\n", hash_alg);
		return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
	}

	/* Set init flag for first operation */
	sha_op.Init = 1;

	/* Clear eom flag until last operation */
	sha_op.Eom = 0;

	/* Need documentation on this b:157610147 */
	sha_op.DataMemType = 2;

	sha_op.Digest = sha_hash;

	sha_op.IntermediateDigest = NULL;

	sha_op.IntermediateMsgLen = 0;

	return VB2_SUCCESS;
}

vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
{
	uint32_t retval;
	sha_op.Data = (uint8_t *)buf;

	if (!sha_op_size_remaining) {
		printk(BIOS_ERR, "got more data than expected.\n");
		return VB2_ERROR_UNKNOWN;
	}

	while (size) {
		sha_op.DataLen = size;

		sha_op_size_remaining -= sha_op.DataLen;

		/* Set eom flag for final operation */
		if (sha_op_size_remaining == 0)
			sha_op.Eom = 1;

		retval = svc_crypto_sha(&sha_op, SHA_GENERIC);
		if (retval) {
			printk(BIOS_ERR, "HW crypto failed - errorcode: %#x\n",
					retval);
			return VB2_ERROR_UNKNOWN;
		}

		/* Clear init flag after first operation */
		if (sha_op.Init == 1)
			sha_op.Init = 0;

		size -= sha_op.DataLen;
	}

	return VB2_SUCCESS;
}

/* Copy the hash back to verstage */
vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
{
	if (sha_op.Eom == 0) {
		printk(BIOS_ERR, "Got less data than expected.\n");
		return VB2_ERROR_UNKNOWN;
	}

	if (digest_size != sha_op.DigestLen) {
		printk(BIOS_ERR, "Digest size does not match expected length.\n");
		return VB2_ERROR_UNKNOWN;
	}

	memcpy(digest, sha_hash, digest_size);

	return VB2_SUCCESS;
}

vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
				  uint8_t *inout,
				  uint32_t *workbuf32, int exp)
{
	/* workbuf32 is guaranteed to be a length of
	 * 3 * key->arrsize * sizeof(uint32_t).
	 * Since PSP expects everything in LE and *inout is BE array,
	 * we'll use workbuf for temporary buffer for endian conversion.
	 */
	struct mod_exp_params mod_exp_param;
	unsigned int key_bytes = key->arrsize * sizeof(uint32_t);
	uint32_t *sig_swapped = workbuf32;
	uint32_t *output_buffer = &workbuf32[key->arrsize];
	uint32_t *inout_32 = (uint32_t *)inout;
	uint32_t retval;
	uint32_t i;

	/* PSP only supports 2K and 4K moduli */
	if (key->sig_alg != VB2_SIG_RSA2048 &&
	    key->sig_alg != VB2_SIG_RSA2048_EXP3 &&
	    key->sig_alg != VB2_SIG_RSA4096) {
		return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
	}

	for (i = 0; i < key->arrsize; i++)
		sig_swapped[i] = swab32(inout_32[key->arrsize - i - 1]);

	mod_exp_param.pExponent = (char *)&exp;
	mod_exp_param.ExpSize = sizeof(exp);
	mod_exp_param.pModulus = (char *)key->n;
	mod_exp_param.ModulusSize = key_bytes;
	mod_exp_param.pMessage = (char *)sig_swapped;
	mod_exp_param.pOutput = (char *)output_buffer;

	retval = svc_modexp(&mod_exp_param);
	if (retval) {
		printk(BIOS_ERR, "HW crypto failed - errorcode: %#x\n",
				retval);
		return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
	}

	/* vboot expects results in *inout with BE, so copy & convert. */
	for (i = 0; i < key->arrsize; i++)
		inout_32[i] = swab32(output_buffer[key->arrsize - i - 1]);

	return VB2_SUCCESS;
}