coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
vboot_crypto.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <2crypto.h>
4 #include <2return_codes.h>
5 #include <bl_uapp/bl_syscall_public.h>
7 #include <console/console.h>
8 #include "psp_verstage.h"
9 #include <stddef.h>
10 #include <string.h>
11 #include <swab.h>
12 #include <vb2_api.h>
13 
14 static struct sha_generic_data sha_op;
16 static uint8_t __attribute__((aligned(32))) sha_hash[64];
17 
18 vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg, uint32_t data_size)
19 {
20  printk(BIOS_DEBUG, "Calculating hash of %d bytes\n", data_size);
21 
22  sha_op_size_remaining = data_size;
23 
24  if (platform_set_sha_op(hash_alg, &sha_op) != 0) {
25  printk(BIOS_INFO, "Unsupported hash_alg %d!\n", hash_alg);
26  return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
27  }
28 
29  /* Set init flag for first operation */
30  sha_op.Init = 1;
31 
32  /* Clear eom flag until last operation */
33  sha_op.Eom = 0;
34 
35  /* Need documentation on this b:157610147 */
36  sha_op.DataMemType = 2;
37 
38  sha_op.Digest = sha_hash;
39 
40  sha_op.IntermediateDigest = NULL;
41 
42  sha_op.IntermediateMsgLen = 0;
43 
44  return VB2_SUCCESS;
45 }
46 
48 {
49  uint32_t retval;
50  sha_op.Data = (uint8_t *) buf;
51 
52  if (!sha_op_size_remaining) {
53  printk(BIOS_ERR, "got more data than expected.\n");
54  return VB2_ERROR_UNKNOWN;
55  }
56 
57  while (size) {
58  sha_op.DataLen = size;
59 
60  sha_op_size_remaining -= sha_op.DataLen;
61 
62  /* Set eom flag for final operation */
63  if (sha_op_size_remaining == 0)
64  sha_op.Eom = 1;
65 
66  retval = svc_crypto_sha(&sha_op, SHA_GENERIC);
67  if (retval) {
68  printk(BIOS_ERR, "HW crypto failed - errorcode: %#x\n",
69  retval);
70  return VB2_ERROR_UNKNOWN;
71  }
72 
73  /* Clear init flag after first operation */
74  if (sha_op.Init == 1)
75  sha_op.Init = 0;
76 
77  size -= sha_op.DataLen;
78  }
79 
80  return VB2_SUCCESS;
81 }
82 
83 /* Copy the hash back to verstage */
84 vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
85 {
86  if (sha_op.Eom == 0) {
87  printk(BIOS_ERR, "Got less data than expected.\n");
88  return VB2_ERROR_UNKNOWN;
89  }
90 
91  if (digest_size != sha_op.DigestLen) {
92  printk(BIOS_ERR, "Digest size does not match expected length.\n");
93  return VB2_ERROR_UNKNOWN;
94  }
95 
96  memcpy(digest, sha_hash, digest_size);
97 
98  return VB2_SUCCESS;
99 }
100 
101 vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
102  uint8_t *inout,
103  uint32_t *workbuf32, int exp)
104 {
105  /* workbuf32 is guaranteed to be a length of
106  * 3 * key->arrsize * sizeof(uint32_t).
107  * Since PSP expects everything in LE and *inout is BE array,
108  * we'll use workbuf for temporary buffer for endian conversion.
109  */
110  struct mod_exp_params mod_exp_param;
111  unsigned int key_bytes = key->arrsize * sizeof(uint32_t);
112  uint32_t *sig_swapped = workbuf32;
113  uint32_t *output_buffer = &workbuf32[key->arrsize];
114  uint32_t *inout_32 = (uint32_t *)inout;
115  uint32_t retval;
116  uint32_t i;
117 
118  /* PSP only supports 2K and 4K moduli */
119  if (key->sig_alg != VB2_SIG_RSA2048 &&
120  key->sig_alg != VB2_SIG_RSA2048_EXP3 &&
121  key->sig_alg != VB2_SIG_RSA4096) {
122  return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
123  }
124 
125  for (i = 0; i < key->arrsize; i++)
126  sig_swapped[i] = swab32(inout_32[key->arrsize - i - 1]);
127 
128  mod_exp_param.pExponent = (char *)&exp;
129  mod_exp_param.ExpSize = sizeof(exp);
130  mod_exp_param.pModulus = (char *)key->n;
131  mod_exp_param.ModulusSize = key_bytes;
132  mod_exp_param.pMessage = (char *)sig_swapped;
133  mod_exp_param.pOutput = (char *)output_buffer;
134 
135  retval = svc_modexp(&mod_exp_param);
136  if (retval) {
137  printk(BIOS_ERR, "HW crypto failed - errorcode: %#x\n",
138  retval);
139  return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
140  }
141 
142  /* vboot expects results in *inout with BE, so copy & convert. */
143  for (i = 0; i < key->arrsize; i++)
144  inout_32[i] = swab32(output_buffer[key->arrsize - i - 1]);
145 
146  return VB2_SUCCESS;
147 }
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
int platform_set_sha_op(enum vb2_hash_algorithm hash_alg, struct sha_generic_data *sha_op)
Definition: chipset.c:22
uint32_t svc_crypto_sha(struct sha_generic_data *sha_op, enum sha_operation_mode sha_mode)
Definition: svc.c:116
uint32_t svc_modexp(struct mod_exp_params *mod_exp_param)
Definition: svc.c:123
#define printk(level,...)
Definition: stdlib.h:16
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static uint8_t * buf
Definition: uart.c:7
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
#define swab32(x)
Definition: swab.h:49
vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg, uint32_t data_size)
Definition: vboot_crypto.c:18
static uint32_t sha_op_size_remaining
Definition: vboot_crypto.c:15
vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
Definition: vboot_crypto.c:84
static struct sha_generic_data sha_op
Definition: vboot_crypto.c:14
static uint8_t sha_hash[64]
Definition: vboot_crypto.c:16
vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
Definition: vboot_crypto.c:47
vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key, uint8_t *inout, uint32_t *workbuf32, int exp)
Definition: vboot_crypto.c:101