OLD | NEW |
---|---|
(Empty) | |
1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | |
2 * Use of this source code is governed by a BSD-style license that can be | |
3 * found in the LICENSE file. | |
4 * | |
5 * Common functions between firmware and kernel verified boot. | |
6 * (Firmware portion) | |
7 */ | |
8 | |
9 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */ | |
10 | |
11 #include "vboot_common.h" | |
12 #include "utility.h" | |
13 | |
14 #include <stdio.h> /* TODO: FOR TESTING */ | |
15 | |
16 char* kVbootErrors[VBOOT_ERROR_MAX] = { | |
17 "Success.", | |
18 "Invalid Image.", | |
19 "Kernel Key Signature Failed.", | |
20 "Invalid Kernel Verification Algorithm.", | |
21 "Preamble Signature Failed.", | |
22 "Kernel Signature Failed.", | |
23 "Wrong Kernel Magic.", | |
24 }; | |
25 | |
26 | |
27 uint64_t OffsetOf(const void *base, const void *ptr) { | |
gauravsh
2010/06/10 14:44:13
since this function assumes 64-bit pointers, would
| |
28 return (uint64_t)(size_t)ptr - (uint64_t)(size_t)base; | |
29 } | |
30 | |
31 | |
32 /* Helper functions to get data pointed to by a public key or signature. */ | |
33 uint8_t* GetPublicKeyData(VbPublicKey* key) { | |
34 return (uint8_t*)key + key->key_offset; | |
35 } | |
36 | |
37 const uint8_t* GetPublicKeyDataC(const VbPublicKey* key) { | |
38 return (const uint8_t*)key + key->key_offset; | |
39 } | |
40 | |
41 uint8_t* GetSignatureData(VbSignature* sig) { | |
42 return (uint8_t*)sig + sig->sig_offset; | |
43 } | |
44 | |
45 const uint8_t* GetSignatureDataC(const VbSignature* sig) { | |
46 return (const uint8_t*)sig + sig->sig_offset; | |
47 } | |
48 | |
49 | |
50 /* Helper functions to verify the data pointed to by a subfield is inside | |
51 * the parent data. Returns 0 if inside, 1 if error. */ | |
52 int VerifyMemberInside(const void* parent, uint64_t parent_size, | |
53 const void* member, uint64_t member_size, | |
54 uint64_t member_data_offset, | |
55 uint64_t member_data_size) { | |
56 uint64_t end = OffsetOf(parent, member); | |
57 | |
58 if (end > parent_size) | |
59 return 1; | |
60 | |
61 if (end + member_size > parent_size) | |
62 return 1; | |
63 | |
64 end += member_data_offset; | |
65 if (end > parent_size) | |
66 return 1; | |
67 if (end + member_data_size > parent_size) | |
68 return 1; | |
69 | |
70 return 0; | |
71 } | |
72 | |
73 | |
74 int VerifyPublicKeyInside(const void* parent, uint64_t parent_size, | |
75 const VbPublicKey* key) { | |
76 return VerifyMemberInside(parent, parent_size, | |
77 key, sizeof(VbPublicKey), | |
78 key->key_offset, key->key_size); | |
79 } | |
80 | |
81 | |
82 int VerifySignatureInside(const void* parent, uint64_t parent_size, | |
83 const VbSignature* sig) { | |
84 return VerifyMemberInside(parent, parent_size, | |
85 sig, sizeof(VbSignature), | |
86 sig->sig_offset, sig->sig_size); | |
87 } | |
88 | |
89 | |
90 RSAPublicKey* PublicKeyToRSA(const VbPublicKey* key) { | |
91 RSAPublicKey *rsa; | |
92 | |
93 if (kNumAlgorithms <= key->algorithm) { | |
94 debug("Invalid algorithm.\n"); | |
95 return NULL; | |
96 } | |
97 if (RSAProcessedKeySize(key->algorithm) != key->key_size) { | |
98 debug("Wrong key size for algorithm\n"); | |
99 return NULL; | |
100 } | |
101 | |
102 rsa = RSAPublicKeyFromBuf(GetPublicKeyDataC(key), key->key_size); | |
103 if (!rsa) | |
104 return NULL; | |
105 | |
106 rsa->algorithm = key->algorithm; | |
107 return rsa; | |
108 } | |
109 | |
110 | |
111 int VerifyData(const uint8_t* data, const VbSignature *sig, | |
112 const RSAPublicKey* key) { | |
113 | |
114 if (sig->sig_size != siglen_map[key->algorithm]) { | |
115 debug("Wrong signature size for algorithm.\n"); | |
116 return 1; | |
117 } | |
118 | |
119 if (!RSAVerifyBinary_f(NULL, key, data, sig->data_size, | |
120 GetSignatureDataC(sig), key->algorithm)) | |
121 return 1; | |
122 | |
123 return 0; | |
124 } | |
125 | |
126 | |
127 int VerifyKeyBlock(const VbKeyBlockHeader* block, uint64_t size, | |
128 const VbPublicKey *key) { | |
129 | |
130 const VbSignature* sig; | |
131 | |
132 /* Sanity checks before attempting signature of data */ | |
133 if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) { | |
134 debug("Not a valid verified boot key block.\n"); | |
135 return 1; | |
136 } | |
137 if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) { | |
138 debug("Incompatible key block header version.\n"); | |
139 return 1; | |
140 } | |
141 if (size < block->key_block_size) { | |
142 debug("Not enough data for key block.\n"); | |
143 return 1; | |
144 } | |
145 | |
146 /* Check signature or hash, depending on whether we have a key. */ | |
147 if (key) { | |
148 /* Check signature */ | |
149 RSAPublicKey* rsa; | |
150 int rv; | |
151 | |
152 sig = &block->key_block_signature; | |
153 | |
154 if (VerifySignatureInside(block, block->key_block_size, sig)) { | |
155 debug("Key block signature off end of block\n"); | |
156 return 1; | |
157 } | |
158 | |
159 if (!((rsa = PublicKeyToRSA(key)))) { | |
160 debug("Invalid public key\n"); | |
161 return 1; | |
162 } | |
163 rv = VerifyData((const uint8_t*)block, sig, rsa); | |
164 RSAPublicKeyFree(rsa); | |
165 | |
166 if (rv) | |
167 return rv; | |
168 | |
169 } else { | |
170 /* Check hash */ | |
171 uint8_t* header_checksum = NULL; | |
172 int rv; | |
173 | |
174 sig = &block->key_block_checksum; | |
175 | |
176 if (VerifySignatureInside(block, block->key_block_size, sig)) { | |
177 debug("Key block hash off end of block\n"); | |
178 return 1; | |
179 } | |
180 if (sig->sig_size != SHA512_DIGEST_SIZE) { | |
181 debug("Wrong hash size for key block.\n"); | |
182 return 1; | |
183 } | |
184 | |
185 header_checksum = DigestBuf((const uint8_t*)block, sig->data_size, | |
186 SHA512_DIGEST_ALGORITHM); | |
187 rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig), | |
188 SHA512_DIGEST_SIZE); | |
189 Free(header_checksum); | |
190 if (rv) { | |
191 debug("Invalid key block hash.\n"); | |
192 return 1; | |
193 } | |
194 } | |
195 | |
196 /* Verify we signed enough data */ | |
197 if (sig->data_size < sizeof(VbKeyBlockHeader)) { | |
198 debug("Didn't sign enough data\n"); | |
199 return 1; | |
200 } | |
201 | |
202 /* Verify data key is inside the block and inside signed data */ | |
203 if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) { | |
204 debug("Data key off end of key block\n"); | |
205 return 1; | |
206 } | |
207 if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) { | |
208 debug("Data key off end of signed data\n"); | |
209 return 1; | |
210 } | |
211 | |
212 /* Success */ | |
213 return 0; | |
214 } | |
215 | |
216 | |
217 int VerifyFirmwarePreamble2(const VbFirmwarePreambleHeader* preamble, | |
218 uint64_t size, const RSAPublicKey* key) { | |
219 | |
220 const VbSignature* sig = &preamble->preamble_signature; | |
221 | |
222 /* TODO: caller needs to make sure key version is valid */ | |
223 | |
224 /* Sanity checks before attempting signature of data */ | |
225 if (preamble->header_version_major != | |
226 FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) { | |
227 debug("Incompatible firmware preamble header version.\n"); | |
228 return 1; | |
229 } | |
230 if (size < preamble->preamble_size) { | |
231 debug("Not enough data for preamble.\n"); | |
232 return 1; | |
233 } | |
234 | |
235 /* Check signature */ | |
236 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) { | |
237 debug("Preamble signature off end of preamble\n"); | |
238 return 1; | |
239 } | |
240 if (VerifyData((const uint8_t*)preamble, sig, key)) { | |
241 debug("Preamble signature validation failed\n"); | |
242 return 1; | |
243 } | |
244 | |
245 /* Verify we signed enough data */ | |
246 if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) { | |
247 debug("Didn't sign enough data\n"); | |
248 return 1; | |
249 } | |
250 | |
251 /* Verify body signature is inside the block */ | |
252 if (VerifySignatureInside(preamble, preamble->preamble_size, | |
253 &preamble->body_signature)) { | |
254 debug("Firmware body signature off end of preamble\n"); | |
255 return 1; | |
256 } | |
257 | |
258 /* Verify kernel subkey is inside the block */ | |
259 if (VerifyPublicKeyInside(preamble, preamble->preamble_size, | |
260 &preamble->kernel_subkey)) { | |
261 debug("Kernel subkey off end of preamble\n"); | |
262 return 1; | |
263 } | |
264 | |
265 /* Success */ | |
266 return 0; | |
267 } | |
268 | |
269 | |
270 int VerifyKernelPreamble2(const VbKernelPreambleHeader* preamble, | |
271 uint64_t size, const RSAPublicKey* key) { | |
272 | |
273 const VbSignature* sig = &preamble->preamble_signature; | |
274 | |
275 /* TODO: caller needs to make sure key version is valid */ | |
276 | |
277 /* Sanity checks before attempting signature of data */ | |
278 if (preamble->header_version_major != KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) { | |
279 debug("Incompatible kernel preamble header version.\n"); | |
280 return 1; | |
281 } | |
282 if (size < preamble->preamble_size) { | |
283 debug("Not enough data for preamble.\n"); | |
284 return 1; | |
285 } | |
286 | |
287 /* Check signature */ | |
288 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) { | |
289 debug("Preamble signature off end of preamble\n"); | |
290 return 1; | |
291 } | |
292 if (VerifyData((const uint8_t*)preamble, sig, key)) { | |
293 debug("Preamble signature validation failed\n"); | |
294 return 1; | |
295 } | |
296 | |
297 /* Verify we signed enough data */ | |
298 if (sig->data_size < sizeof(VbKernelPreambleHeader)) { | |
299 debug("Didn't sign enough data\n"); | |
300 return 1; | |
301 } | |
302 | |
303 /* Verify body signature is inside the block */ | |
304 if (VerifySignatureInside(preamble, preamble->preamble_size, | |
305 &preamble->body_signature)) { | |
306 debug("Kernel body signature off end of preamble\n"); | |
307 return 1; | |
308 } | |
309 | |
310 /* Success */ | |
311 return 0; | |
312 } | |
OLD | NEW |