xref: /aosp_15_r20/external/vboot_reference/firmware/2lib/2secdata_kernel.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2015 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Secure storage APIs - kernel version space
6  */
7 
8 #include "2common.h"
9 #include "2crc8.h"
10 #include "2misc.h"
11 #include "2secdata.h"
12 #include "2secdata_struct.h"
13 #include "2sysincludes.h"
14 
15 #define MAJOR_VER(x) (((x) & 0xf0) >> 4)
16 #define MINOR_VER(x) ((x) & 0x0f)
17 
is_v0(struct vb2_context * ctx)18 static inline int is_v0(struct vb2_context *ctx)
19 {
20 	struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
21 	return MAJOR_VER(sec->struct_version) == 0;
22 }
23 
24 /**
25  * Calculate crc8 of kernel secure storage.
26  *
27  * @param ctx		Context pointer
28  * @return Calculated crc8 value.
29  */
secdata_kernel_crc(struct vb2_context * ctx)30 static uint8_t secdata_kernel_crc(struct vb2_context *ctx)
31 {
32 	size_t offset, size;
33 
34 	if (is_v0(ctx)) {
35 		offset = 0;
36 		size = offsetof(struct vb2_secdata_kernel_v0, crc8);
37 	} else {
38 		struct vb2_secdata_kernel_v1 *sec
39 			= (void *)ctx->secdata_kernel;
40 		offset = offsetof(struct vb2_secdata_kernel_v1, flags);
41 		size = sec->struct_size - offset;
42 	}
43 
44 	return vb2_crc8(ctx->secdata_kernel + offset, size);
45 }
46 
secdata_kernel_check_v0(struct vb2_context * ctx,uint8_t * size)47 static vb2_error_t secdata_kernel_check_v0(struct vb2_context *ctx,
48 					   uint8_t *size)
49 {
50 	struct vb2_secdata_kernel_v0 *sec = (void *)ctx->secdata_kernel;
51 	uint8_t ver = sec->struct_version;
52 
53 	if (MINOR_VER(ver) != MINOR_VER(VB2_SECDATA_KERNEL_VERSION_V02)) {
54 		VB2_DEBUG("secdata_kernel: bad struct_version (%d.%d)\n",
55 			  MAJOR_VER(ver), MINOR_VER(ver));
56 		return VB2_ERROR_SECDATA_KERNEL_VERSION;
57 	}
58 
59 	*size = VB2_SECDATA_KERNEL_SIZE_V02;
60 
61 	/* Verify CRC */
62 	if (sec->crc8 != secdata_kernel_crc(ctx)) {
63 		VB2_DEBUG("secdata_kernel: bad CRC\n");
64 		return VB2_ERROR_SECDATA_KERNEL_CRC;
65 	}
66 
67 	/* Verify UID */
68 	if (sec->uid != VB2_SECDATA_KERNEL_UID) {
69 		VB2_DEBUG("secdata_kernel: bad UID\n");
70 		return VB2_ERROR_SECDATA_KERNEL_UID;
71 	}
72 
73 	return VB2_SUCCESS;
74 }
75 
secdata_kernel_check_v1(struct vb2_context * ctx,uint8_t * size)76 static vb2_error_t secdata_kernel_check_v1(struct vb2_context *ctx,
77 					   uint8_t *size)
78 {
79 	struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
80 	uint8_t ver = sec->struct_version;
81 
82 	if (MAJOR_VER(ver) != MAJOR_VER(VB2_SECDATA_KERNEL_VERSION_V10)) {
83 		VB2_DEBUG("secdata_kernel: bad struct_version (%d.%d)\n",
84 			  MAJOR_VER(ver), MINOR_VER(ver));
85 		return VB2_ERROR_SECDATA_KERNEL_VERSION;
86 	}
87 
88 	if (sec->struct_size < VB2_SECDATA_KERNEL_SIZE_V10 ||
89 			VB2_SECDATA_KERNEL_MAX_SIZE < sec->struct_size) {
90 		VB2_DEBUG("secdata_kernel: bad struct_size (%d)\n",
91 			  sec->struct_size);
92 		return VB2_ERROR_SECDATA_KERNEL_STRUCT_SIZE;
93 	}
94 
95 	if (*size < sec->struct_size) {
96 		VB2_DEBUG("secdata_kernel: incomplete data (missing %d bytes)\n",
97 			  sec->struct_size - *size);
98 		*size = sec->struct_size;
99 		return VB2_ERROR_SECDATA_KERNEL_INCOMPLETE;
100 	}
101 
102 	/*
103 	 * In case larger data should be passed, kindly let the caller know
104 	 * the right size.
105 	 */
106 	*size = sec->struct_size;
107 
108 	/* Verify CRC */
109 	if (sec->crc8 != secdata_kernel_crc(ctx)) {
110 		VB2_DEBUG("secdata_kernel: bad CRC\n");
111 		return VB2_ERROR_SECDATA_KERNEL_CRC;
112 	}
113 
114 	return VB2_SUCCESS;
115 }
116 
vb2api_secdata_kernel_check(struct vb2_context * ctx,uint8_t * size)117 vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx, uint8_t *size)
118 {
119 	if (*size < VB2_SECDATA_KERNEL_MIN_SIZE) {
120 		VB2_DEBUG("secdata_kernel: data size too small!\n");
121 		*size = VB2_SECDATA_KERNEL_MIN_SIZE;
122 		return VB2_ERROR_SECDATA_KERNEL_INCOMPLETE;
123 	}
124 
125 	if (is_v0(ctx))
126 		return secdata_kernel_check_v0(ctx, size);
127 	else
128 		return secdata_kernel_check_v1(ctx, size);
129 }
130 
vb2api_secdata_kernel_create(struct vb2_context * ctx)131 uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
132 {
133 	struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
134 
135 	/* Populate the struct */
136 	memset(sec, 0, sizeof(*sec));
137 	sec->struct_version = VB2_SECDATA_KERNEL_VERSION_LATEST;
138 	sec->struct_size = sizeof(*sec);
139 	sec->crc8 = secdata_kernel_crc(ctx);
140 
141 	/* Mark as changed */
142 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
143 
144 	return sizeof(*sec);
145 }
146 
147 /* For TPM 1.2 */
vb2api_secdata_kernel_create_v0(struct vb2_context * ctx)148 uint32_t vb2api_secdata_kernel_create_v0(struct vb2_context *ctx)
149 {
150 	struct vb2_secdata_kernel_v0 *sec = (void *)ctx->secdata_kernel;
151 
152 	/* Clear the entire struct */
153 	memset(sec, 0, sizeof(*sec));
154 
155 	/* Set to current version */
156 	sec->struct_version = VB2_SECDATA_KERNEL_VERSION_V02;
157 
158 	/* Set UID */
159 	sec->uid = VB2_SECDATA_KERNEL_UID;
160 
161 	/* Calculate initial CRC */
162 	sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel_v0, crc8));
163 
164 	/* Mark as changed */
165 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
166 
167 	return sizeof(*sec);
168 }
169 
vb2_secdata_kernel_init(struct vb2_context * ctx)170 vb2_error_t vb2_secdata_kernel_init(struct vb2_context *ctx)
171 {
172 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
173 	uint8_t size = VB2_SECDATA_KERNEL_MAX_SIZE;
174 
175 	VB2_TRY(vb2api_secdata_kernel_check(ctx, &size));
176 
177 	/* Set status flag */
178 	sd->status |= VB2_SD_STATUS_SECDATA_KERNEL_INIT;
179 
180 	return VB2_SUCCESS;
181 }
182 
183 test_mockable
vb2_secdata_kernel_get(struct vb2_context * ctx,enum vb2_secdata_kernel_param param)184 uint32_t vb2_secdata_kernel_get(struct vb2_context *ctx,
185 				enum vb2_secdata_kernel_param param)
186 {
187 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
188 	const char *msg;
189 	const struct vb2_secdata_kernel_v0 *v0 = (void *)ctx->secdata_kernel;
190 	const struct vb2_secdata_kernel_v1 *v1 = (void *)ctx->secdata_kernel;
191 
192 	if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
193 		msg = "get before init";
194 		goto fail;
195 	}
196 
197 	switch (param) {
198 	case VB2_SECDATA_KERNEL_VERSIONS:
199 		return is_v0(ctx) ? v0->kernel_versions : v1->kernel_versions;
200 	case VB2_SECDATA_KERNEL_FLAGS:
201 		if (is_v0(ctx)) {
202 			VB2_DEBUG("VB2_SECDATA_KERNEL_FLAGS not supported for "
203 				  "secdata_kernel v0, return 0\n");
204 			return 0;
205 		}
206 		return v1->flags;
207 	default:
208 		msg = "invalid param";
209 	}
210 
211  fail:
212 	VB2_REC_OR_DIE(ctx, "%s\n", msg);
213 	return 0;
214 }
215 
216 test_mockable
vb2_secdata_kernel_set(struct vb2_context * ctx,enum vb2_secdata_kernel_param param,uint32_t value)217 void vb2_secdata_kernel_set(struct vb2_context *ctx,
218 			    enum vb2_secdata_kernel_param param,
219 			    uint32_t value)
220 {
221 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
222 	const char *msg;
223 	struct vb2_secdata_kernel_v0 *v0 = (void *)ctx->secdata_kernel;
224 	struct vb2_secdata_kernel_v1 *v1 = (void *)ctx->secdata_kernel;
225 	uint32_t *ptr;
226 
227 	if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
228 		msg = "set before init";
229 		goto fail;
230 	}
231 
232 	/* If not changing the value, just return early */
233 	if (value == vb2_secdata_kernel_get(ctx, param))
234 		return;
235 
236 	switch (param) {
237 	case VB2_SECDATA_KERNEL_VERSIONS:
238 		ptr = is_v0(ctx) ? &v0->kernel_versions : &v1->kernel_versions;
239 		VB2_DEBUG("secdata_kernel versions updated from %#x to %#x\n",
240 			  *ptr, value);
241 		*ptr = value;
242 		break;
243 	case VB2_SECDATA_KERNEL_FLAGS:
244 		if (is_v0(ctx)) {
245 			VB2_DEBUG("VB2_SECDATA_KERNEL_FLAGS not supported for "
246 				  "secdata_kernel v0, silently ignore\n");
247 			return;
248 		}
249 
250 		/* Make sure flags is in valid range */
251 		if (value > UINT8_MAX) {
252 			msg = "flags out of range";
253 			goto fail;
254 		}
255 
256 		VB2_DEBUG("secdata_kernel flags updated from %#x to %#x\n",
257 			  v1->flags, value);
258 		v1->flags = value;
259 		break;
260 	default:
261 		msg = "invalid param";
262 		goto fail;
263 	}
264 
265 	if (is_v0(ctx))
266 		v0->crc8 = secdata_kernel_crc(ctx);
267 	else
268 		v1->crc8 = secdata_kernel_crc(ctx);
269 
270 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
271 	return;
272 
273  fail:
274 	VB2_REC_OR_DIE(ctx, "%s\n", msg);
275 }
276 
277 test_mockable
vb2_secdata_kernel_get_ec_hash(struct vb2_context * ctx)278 const uint8_t *vb2_secdata_kernel_get_ec_hash(struct vb2_context *ctx)
279 {
280 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
281 	struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
282 
283 	if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
284 		VB2_REC_OR_DIE(ctx, "Get kernel secdata before init\n");
285 		return NULL;
286 	}
287 	if (is_v0(ctx)) {
288 		VB2_DEBUG("kernel secdata v.0* doesn't support EC hash\n");
289 		return NULL;
290 	}
291 
292 	return sec->ec_hash;
293 }
294 
295 test_mockable
vb2_secdata_kernel_set_ec_hash(struct vb2_context * ctx,const uint8_t * sha256)296 void vb2_secdata_kernel_set_ec_hash(struct vb2_context *ctx,
297 				    const uint8_t *sha256)
298 {
299 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
300 	struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
301 
302 	if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
303 		VB2_REC_OR_DIE(ctx, "Get kernel secdata before init\n");
304 		return;
305 	}
306 	if (is_v0(ctx)) {
307 		VB2_REC_OR_DIE(ctx, "Invalid version of kernel secdata\n");
308 		return;
309 	}
310 
311 	memcpy(sec->ec_hash, sha256, sizeof(sec->ec_hash));
312 	sec->crc8 = secdata_kernel_crc(ctx);
313 
314 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
315 
316 	return;
317 }
318 
vb2api_get_kernel_rollback_version(struct vb2_context * ctx)319 uint32_t vb2api_get_kernel_rollback_version(struct vb2_context *ctx)
320 {
321 	return vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
322 }
323