xref: /aosp_15_r20/external/vboot_reference/host/lib21/host_common.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2014 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  * Signature validation functions
6  */
7 
8 #include "2common.h"
9 #include "2rsa.h"
10 #include "2sha.h"
11 #include "2sysincludes.h"
12 #include "host_common21.h"
13 
vb21_common_desc(const void * buf)14 const char *vb21_common_desc(const void *buf)
15 {
16 	const struct vb21_struct_common *c = buf;
17 
18 	return c->desc_size ? (const char *)c + c->fixed_size : "";
19 }
20 
vb21_verify_common_header(const void * parent,uint32_t parent_size)21 vb2_error_t vb21_verify_common_header(const void *parent, uint32_t parent_size)
22 {
23 	const struct vb21_struct_common *c = parent;
24 
25 	/* Parent buffer size must be at least the claimed total size */
26 	if (parent_size < c->total_size)
27 		return VB2_ERROR_COMMON_TOTAL_SIZE;
28 
29 	/*
30 	 * And big enough for the fixed size, which itself must be at least as
31 	 * big as the common struct header.
32 	 */
33 	if (c->total_size < c->fixed_size || c->fixed_size < sizeof(*c))
34 		return VB2_ERROR_COMMON_FIXED_SIZE;
35 
36 	/* Make sure sizes are all multiples of 32 bits */
37 	if (!vb2_aligned(c->total_size, sizeof(uint32_t)))
38 		return VB2_ERROR_COMMON_TOTAL_UNALIGNED;
39 	if (!vb2_aligned(c->fixed_size, sizeof(uint32_t)))
40 		return VB2_ERROR_COMMON_FIXED_UNALIGNED;
41 	if (!vb2_aligned(c->desc_size, sizeof(uint32_t)))
42 		return VB2_ERROR_COMMON_DESC_UNALIGNED;
43 
44 	/* Check description */
45 	if (c->desc_size > 0) {
46 		/* Make sure description fits and doesn't wrap */
47 		if (c->fixed_size + c->desc_size < c->fixed_size)
48 			return VB2_ERROR_COMMON_DESC_WRAPS;
49 		if (c->fixed_size + c->desc_size > c->total_size)
50 			return VB2_ERROR_COMMON_DESC_SIZE;
51 
52 		/* Description must be null-terminated */
53 		if (vb21_common_desc(c)[c->desc_size - 1] != 0)
54 			return VB2_ERROR_COMMON_DESC_TERMINATOR;
55 	}
56 
57 	return VB2_SUCCESS;
58 }
59 
vb21_verify_common_member(const void * parent,uint32_t * min_offset,uint32_t member_offset,uint32_t member_size)60 vb2_error_t vb21_verify_common_member(const void *parent, uint32_t *min_offset,
61 				      uint32_t member_offset,
62 				      uint32_t member_size)
63 {
64 	const struct vb21_struct_common *c = parent;
65 	uint32_t member_end = member_offset + member_size;
66 
67 	/* Make sure member doesn't wrap */
68 	if (member_end < member_offset)
69 		return VB2_ERROR_COMMON_MEMBER_WRAPS;
70 
71 	/* Member offset and size must be 32-bit aligned */
72 	if (!vb2_aligned(member_offset, sizeof(uint32_t)) ||
73 	    !vb2_aligned(member_size, sizeof(uint32_t)))
74 		return VB2_ERROR_COMMON_MEMBER_UNALIGNED;
75 
76 	/* Initialize minimum offset if necessary */
77 	if (!*min_offset)
78 		*min_offset = c->fixed_size + c->desc_size;
79 
80 	/* Member must be after minimum offset */
81 	if (member_offset < *min_offset)
82 		return VB2_ERROR_COMMON_MEMBER_OVERLAP;
83 
84 	/* Member must end before total size */
85 	if (member_end > c->total_size)
86 		return VB2_ERROR_COMMON_MEMBER_SIZE;
87 
88 	/* Update minimum offset for subsequent checks */
89 	*min_offset = member_end;
90 
91 	return VB2_SUCCESS;
92 }
93 
vb21_verify_common_subobject(const void * parent,uint32_t * min_offset,uint32_t member_offset)94 vb2_error_t vb21_verify_common_subobject(const void *parent,
95 					 uint32_t *min_offset,
96 					 uint32_t member_offset)
97 {
98 	const struct vb21_struct_common *p = parent;
99 	const struct vb21_struct_common *m =
100 		(const struct vb21_struct_common *)
101 		((const uint8_t *)parent + member_offset);
102 	vb2_error_t rv;
103 
104 	/*
105 	 * Verify the parent has space at the member offset for the common
106 	 * header.
107 	 */
108 	rv = vb21_verify_common_member(parent, min_offset, member_offset,
109 				      sizeof(*m));
110 	if (rv)
111 		return rv;
112 
113 	/*
114 	 * Now it's safe to look at the member's header, and verify any
115 	 * additional data for the object past its common header fits in the
116 	 * parent.
117 	 */
118 	rv = vb21_verify_common_header(m, p->total_size - member_offset);
119 	if (rv)
120 		return rv;
121 
122 	/* Advance the min offset to the end of the subobject */
123 	*min_offset = member_offset + m->total_size;
124 
125 	return VB2_SUCCESS;
126 }
127 
vb2_sig_size(enum vb2_signature_algorithm sig_alg,enum vb2_hash_algorithm hash_alg)128 uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg,
129 		      enum vb2_hash_algorithm hash_alg)
130 {
131 	uint32_t digest_size = vb2_digest_size(hash_alg);
132 
133 	/* Fail if we don't support the hash algorithm */
134 	if (!digest_size)
135 		return 0;
136 
137 	/* Handle unsigned hashes */
138 	if (sig_alg == VB2_SIG_NONE)
139 		return digest_size;
140 
141 	return vb2_rsa_sig_size(sig_alg);
142 }
143 
vb2_hash_id(enum vb2_hash_algorithm hash_alg)144 const struct vb2_id *vb2_hash_id(enum vb2_hash_algorithm hash_alg)
145 {
146 	switch(hash_alg) {
147 #ifdef VB2_SUPPORT_SHA1
148 	case VB2_HASH_SHA1:
149 		{
150 			static const struct vb2_id id = VB2_ID_NONE_SHA1;
151 			return &id;
152 		}
153 #endif
154 #ifdef VB2_SUPPORT_SHA256
155 	case VB2_HASH_SHA256:
156 		{
157 			static const struct vb2_id id = VB2_ID_NONE_SHA256;
158 			return &id;
159 		}
160 #endif
161 #ifdef VB2_SUPPORT_SHA512
162 	case VB2_HASH_SHA512:
163 		{
164 			static const struct vb2_id id = VB2_ID_NONE_SHA512;
165 			return &id;
166 		}
167 #endif
168 	default:
169 		return NULL;
170 	}
171 }
172 
vb21_verify_signature(const struct vb21_signature * sig,uint32_t size)173 vb2_error_t vb21_verify_signature(const struct vb21_signature *sig,
174 				  uint32_t size)
175 {
176 	uint32_t min_offset = 0;
177 	uint32_t expect_sig_size;
178 	vb2_error_t rv;
179 
180 	/* Check magic number */
181 	if (sig->c.magic != VB21_MAGIC_SIGNATURE)
182 		return VB2_ERROR_SIG_MAGIC;
183 
184 	/* Make sure common header is good */
185 	rv = vb21_verify_common_header(sig, size);
186 	if (rv)
187 		return rv;
188 
189 	/*
190 	 * Check for compatible version.  No need to check minor version, since
191 	 * that's compatible across readers matching the major version, and we
192 	 * haven't added any new fields.
193 	 */
194 	if (sig->c.struct_version_major != VB21_SIGNATURE_VERSION_MAJOR)
195 		return VB2_ERROR_SIG_VERSION;
196 
197 	/* Make sure header is big enough for signature */
198 	if (sig->c.fixed_size < sizeof(*sig))
199 		return VB2_ERROR_SIG_HEADER_SIZE;
200 
201 	/* Make sure signature data is inside */
202 	rv = vb21_verify_common_member(sig, &min_offset,
203 				      sig->sig_offset, sig->sig_size);
204 	if (rv)
205 		return rv;
206 
207 	/* Make sure signature size is correct for the algorithm */
208 	expect_sig_size = vb2_sig_size(sig->sig_alg, sig->hash_alg);
209 	if (!expect_sig_size)
210 		return VB2_ERROR_SIG_ALGORITHM;
211 	if (sig->sig_size != expect_sig_size)
212 		return VB2_ERROR_SIG_SIZE;
213 
214 	return VB2_SUCCESS;
215 }
216 
217 /**
218  * Return the signature data for a signature
219  */
vb21_signature_data(struct vb21_signature * sig)220 static uint8_t *vb21_signature_data(struct vb21_signature *sig)
221 {
222 	return (uint8_t *)sig + sig->sig_offset;
223 }
224 
vb21_verify_digest(const struct vb2_public_key * key,struct vb21_signature * sig,const uint8_t * digest,const struct vb2_workbuf * wb)225 vb2_error_t vb21_verify_digest(const struct vb2_public_key *key,
226 			       struct vb21_signature *sig,
227 			       const uint8_t *digest,
228 			       const struct vb2_workbuf *wb)
229 {
230 	uint32_t key_sig_size = vb2_sig_size(key->sig_alg, key->hash_alg);
231 
232 	/* If we can't figure out the signature size, key algorithm was bad */
233 	if (!key_sig_size)
234 		return VB2_ERROR_VDATA_ALGORITHM;
235 
236 	/* Make sure the signature and key algorithms match */
237 	if (key->sig_alg != sig->sig_alg || key->hash_alg != sig->hash_alg)
238 		return VB2_ERROR_VDATA_ALGORITHM_MISMATCH;
239 
240 	if (sig->sig_size != key_sig_size)
241 		return VB2_ERROR_VDATA_SIG_SIZE;
242 
243 	if (key->sig_alg == VB2_SIG_NONE) {
244 		/* Bare hash */
245 		if (vb2_safe_memcmp(vb21_signature_data(sig),
246 				    digest, key_sig_size))
247 			return VB2_ERROR_VDATA_VERIFY_DIGEST;
248 
249 		return VB2_SUCCESS;
250 	} else {
251 		/* RSA-signed digest */
252 		return vb2_rsa_verify_digest(key,
253 					     vb21_signature_data(sig),
254 					     digest, wb);
255 	}
256 }
257 
vb21_verify_data(const void * data,uint32_t size,struct vb21_signature * sig,const struct vb2_public_key * key,const struct vb2_workbuf * wb)258 vb2_error_t vb21_verify_data(const void *data, uint32_t size,
259 			     struct vb21_signature *sig,
260 			     const struct vb2_public_key *key,
261 			     const struct vb2_workbuf *wb)
262 {
263 	struct vb2_workbuf wblocal = *wb;
264 	struct vb2_digest_context *dc;
265 	uint8_t *digest;
266 	uint32_t digest_size;
267 	vb2_error_t rv;
268 
269 	if (sig->data_size != size) {
270 		VB2_DEBUG("Wrong amount of data signed.\n");
271 		return VB2_ERROR_VDATA_SIZE;
272 	}
273 
274 	/* Digest goes at start of work buffer */
275 	digest_size = vb2_digest_size(key->hash_alg);
276 	if (!digest_size)
277 		return VB2_ERROR_VDATA_DIGEST_SIZE;
278 
279 	digest = vb2_workbuf_alloc(&wblocal, digest_size);
280 	if (!digest)
281 		return VB2_ERROR_VDATA_WORKBUF_DIGEST;
282 
283 	/* Hashing requires temp space for the context */
284 	dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
285 	if (!dc)
286 		return VB2_ERROR_VDATA_WORKBUF_HASHING;
287 
288 	rv = vb2_digest_init(dc, false, key->hash_alg, 0);
289 	if (rv)
290 		return rv;
291 
292 	rv = vb2_digest_extend(dc, data, size);
293 	if (rv)
294 		return rv;
295 
296 	rv = vb2_digest_finalize(dc, digest, digest_size);
297 	if (rv)
298 		return rv;
299 
300 	vb2_workbuf_free(&wblocal, sizeof(*dc));
301 
302 	return vb21_verify_digest(key, sig, digest, &wblocal);
303 }
304