blob: f76eed45abc0655a93c77099e171773f6365ef0e [file] [log] [blame]
Randall Spanglerd1836442010-06-10 09:59:04 -07001/* 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
Randall Spanglerd1836442010-06-10 09:59:04 -07009
10#include "vboot_common.h"
11#include "utility.h"
12
Randall Spanglerd1836442010-06-10 09:59:04 -070013
14char* kVbootErrors[VBOOT_ERROR_MAX] = {
15 "Success.",
Randall Spangler83c88cf2010-06-11 16:14:18 -070016 "Key block invalid.",
17 "Key block signature failed.",
18 "Key block hash failed.",
19 "Public key invalid.",
20 "Preamble invalid.",
21 "Preamble signature check failed.",
Randall Spanglerd1836442010-06-10 09:59:04 -070022};
23
24
25uint64_t OffsetOf(const void *base, const void *ptr) {
26 return (uint64_t)(size_t)ptr - (uint64_t)(size_t)base;
27}
28
29
30/* Helper functions to get data pointed to by a public key or signature. */
31uint8_t* GetPublicKeyData(VbPublicKey* key) {
32 return (uint8_t*)key + key->key_offset;
33}
34
35const uint8_t* GetPublicKeyDataC(const VbPublicKey* key) {
36 return (const uint8_t*)key + key->key_offset;
37}
38
39uint8_t* GetSignatureData(VbSignature* sig) {
40 return (uint8_t*)sig + sig->sig_offset;
41}
42
43const uint8_t* GetSignatureDataC(const VbSignature* sig) {
44 return (const uint8_t*)sig + sig->sig_offset;
45}
46
47
48/* Helper functions to verify the data pointed to by a subfield is inside
49 * the parent data. Returns 0 if inside, 1 if error. */
50int VerifyMemberInside(const void* parent, uint64_t parent_size,
51 const void* member, uint64_t member_size,
52 uint64_t member_data_offset,
53 uint64_t member_data_size) {
54 uint64_t end = OffsetOf(parent, member);
55
56 if (end > parent_size)
57 return 1;
58
59 if (end + member_size > parent_size)
60 return 1;
61
62 end += member_data_offset;
63 if (end > parent_size)
64 return 1;
65 if (end + member_data_size > parent_size)
66 return 1;
67
68 return 0;
69}
70
71
72int VerifyPublicKeyInside(const void* parent, uint64_t parent_size,
73 const VbPublicKey* key) {
74 return VerifyMemberInside(parent, parent_size,
75 key, sizeof(VbPublicKey),
76 key->key_offset, key->key_size);
77}
78
79
80int VerifySignatureInside(const void* parent, uint64_t parent_size,
81 const VbSignature* sig) {
82 return VerifyMemberInside(parent, parent_size,
83 sig, sizeof(VbSignature),
84 sig->sig_offset, sig->sig_size);
85}
86
87
Randall Spanglera55e5ca2010-06-15 18:45:09 -070088void PublicKeyInit(VbPublicKey* key, uint8_t* key_data, uint64_t key_size) {
89 key->key_offset = OffsetOf(key, key_data);
90 key->key_size = key_size;
91 key->algorithm = kNumAlgorithms; /* Key not present yet */
92 key->key_version = 0;
93}
94
95
96int PublicKeyCopy(VbPublicKey* dest, const VbPublicKey* src) {
97 if (dest->key_size < src->key_size)
98 return 1;
99
100 dest->key_size = src->key_size;
101 dest->algorithm = src->algorithm;
102 dest->key_version = src->key_version;
103 Memcpy(GetPublicKeyData(dest), GetPublicKeyDataC(src), src->key_size);
104 return 0;
105}
106
107
Randall Spanglerd1836442010-06-10 09:59:04 -0700108RSAPublicKey* PublicKeyToRSA(const VbPublicKey* key) {
109 RSAPublicKey *rsa;
110
111 if (kNumAlgorithms <= key->algorithm) {
112 debug("Invalid algorithm.\n");
113 return NULL;
114 }
115 if (RSAProcessedKeySize(key->algorithm) != key->key_size) {
116 debug("Wrong key size for algorithm\n");
117 return NULL;
118 }
119
120 rsa = RSAPublicKeyFromBuf(GetPublicKeyDataC(key), key->key_size);
121 if (!rsa)
122 return NULL;
123
124 rsa->algorithm = key->algorithm;
125 return rsa;
126}
127
128
129int VerifyData(const uint8_t* data, const VbSignature *sig,
130 const RSAPublicKey* key) {
131
132 if (sig->sig_size != siglen_map[key->algorithm]) {
133 debug("Wrong signature size for algorithm.\n");
134 return 1;
135 }
136
137 if (!RSAVerifyBinary_f(NULL, key, data, sig->data_size,
138 GetSignatureDataC(sig), key->algorithm))
139 return 1;
140
141 return 0;
142}
143
144
Randall Spangler39ed88e2010-06-15 14:53:01 -0700145int VerifyDigest(const uint8_t* digest, const VbSignature *sig,
146 const RSAPublicKey* key) {
147
148 if (sig->sig_size != siglen_map[key->algorithm]) {
149 debug("Wrong signature size for algorithm.\n");
150 return 1;
151 }
152
153 if (!RSAVerifyBinaryWithDigest_f(NULL, key, digest,
154 GetSignatureDataC(sig), key->algorithm))
155 return 1;
156
157 return 0;
158}
159
160
Randall Spangler729b8722010-06-11 11:16:20 -0700161int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size,
Randall Spanglerd1836442010-06-10 09:59:04 -0700162 const VbPublicKey *key) {
163
164 const VbSignature* sig;
165
166 /* Sanity checks before attempting signature of data */
167 if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) {
168 debug("Not a valid verified boot key block.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700169 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700170 }
171 if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) {
172 debug("Incompatible key block header version.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700173 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700174 }
175 if (size < block->key_block_size) {
176 debug("Not enough data for key block.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700177 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700178 }
179
180 /* Check signature or hash, depending on whether we have a key. */
181 if (key) {
182 /* Check signature */
183 RSAPublicKey* rsa;
184 int rv;
185
186 sig = &block->key_block_signature;
187
188 if (VerifySignatureInside(block, block->key_block_size, sig)) {
189 debug("Key block signature off end of block\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700190 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700191 }
192
193 if (!((rsa = PublicKeyToRSA(key)))) {
194 debug("Invalid public key\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700195 return VBOOT_PUBLIC_KEY_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700196 }
197 rv = VerifyData((const uint8_t*)block, sig, rsa);
198 RSAPublicKeyFree(rsa);
Randall Spanglerd1836442010-06-10 09:59:04 -0700199 if (rv)
Randall Spangler83c88cf2010-06-11 16:14:18 -0700200 return VBOOT_KEY_BLOCK_SIGNATURE;
Randall Spanglerd1836442010-06-10 09:59:04 -0700201
202 } else {
203 /* Check hash */
204 uint8_t* header_checksum = NULL;
205 int rv;
206
207 sig = &block->key_block_checksum;
208
209 if (VerifySignatureInside(block, block->key_block_size, sig)) {
210 debug("Key block hash off end of block\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700211 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700212 }
213 if (sig->sig_size != SHA512_DIGEST_SIZE) {
214 debug("Wrong hash size for key block.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700215 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700216 }
217
218 header_checksum = DigestBuf((const uint8_t*)block, sig->data_size,
219 SHA512_DIGEST_ALGORITHM);
220 rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig),
221 SHA512_DIGEST_SIZE);
222 Free(header_checksum);
223 if (rv) {
224 debug("Invalid key block hash.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700225 return VBOOT_KEY_BLOCK_HASH;
Randall Spanglerd1836442010-06-10 09:59:04 -0700226 }
227 }
228
229 /* Verify we signed enough data */
230 if (sig->data_size < sizeof(VbKeyBlockHeader)) {
231 debug("Didn't sign enough data\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700232 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700233 }
234
235 /* Verify data key is inside the block and inside signed data */
236 if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) {
237 debug("Data key off end of key block\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700238 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700239 }
240 if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) {
241 debug("Data key off end of signed data\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700242 return VBOOT_KEY_BLOCK_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700243 }
244
245 /* Success */
Randall Spangler83c88cf2010-06-11 16:14:18 -0700246 return VBOOT_SUCCESS;
Randall Spanglerd1836442010-06-10 09:59:04 -0700247}
248
249
250int VerifyFirmwarePreamble2(const VbFirmwarePreambleHeader* preamble,
251 uint64_t size, const RSAPublicKey* key) {
252
253 const VbSignature* sig = &preamble->preamble_signature;
254
Randall Spanglerd1836442010-06-10 09:59:04 -0700255 /* Sanity checks before attempting signature of data */
256 if (preamble->header_version_major !=
257 FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
258 debug("Incompatible firmware preamble header version.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700259 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700260 }
261 if (size < preamble->preamble_size) {
262 debug("Not enough data for preamble.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700263 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700264 }
265
266 /* Check signature */
267 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
268 debug("Preamble signature off end of preamble\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700269 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700270 }
271 if (VerifyData((const uint8_t*)preamble, sig, key)) {
272 debug("Preamble signature validation failed\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700273 return VBOOT_PREAMBLE_SIGNATURE;
Randall Spanglerd1836442010-06-10 09:59:04 -0700274 }
275
276 /* Verify we signed enough data */
277 if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) {
278 debug("Didn't sign enough data\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700279 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700280 }
281
282 /* Verify body signature is inside the block */
283 if (VerifySignatureInside(preamble, preamble->preamble_size,
284 &preamble->body_signature)) {
285 debug("Firmware body signature off end of preamble\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700286 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700287 }
288
289 /* Verify kernel subkey is inside the block */
290 if (VerifyPublicKeyInside(preamble, preamble->preamble_size,
291 &preamble->kernel_subkey)) {
292 debug("Kernel subkey off end of preamble\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700293 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700294 }
295
296 /* Success */
Randall Spangler83c88cf2010-06-11 16:14:18 -0700297 return VBOOT_SUCCESS;
Randall Spanglerd1836442010-06-10 09:59:04 -0700298}
299
300
301int VerifyKernelPreamble2(const VbKernelPreambleHeader* preamble,
302 uint64_t size, const RSAPublicKey* key) {
303
304 const VbSignature* sig = &preamble->preamble_signature;
305
Randall Spanglerd1836442010-06-10 09:59:04 -0700306 /* Sanity checks before attempting signature of data */
307 if (preamble->header_version_major != KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) {
308 debug("Incompatible kernel preamble header version.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700309 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700310 }
311 if (size < preamble->preamble_size) {
312 debug("Not enough data for preamble.\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700313 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700314 }
315
316 /* Check signature */
317 if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
318 debug("Preamble signature off end of preamble\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700319 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700320 }
321 if (VerifyData((const uint8_t*)preamble, sig, key)) {
322 debug("Preamble signature validation failed\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700323 return VBOOT_PREAMBLE_SIGNATURE;
Randall Spanglerd1836442010-06-10 09:59:04 -0700324 }
325
326 /* Verify we signed enough data */
327 if (sig->data_size < sizeof(VbKernelPreambleHeader)) {
328 debug("Didn't sign enough data\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700329 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700330 }
331
332 /* Verify body signature is inside the block */
333 if (VerifySignatureInside(preamble, preamble->preamble_size,
334 &preamble->body_signature)) {
335 debug("Kernel body signature off end of preamble\n");
Randall Spangler83c88cf2010-06-11 16:14:18 -0700336 return VBOOT_PREAMBLE_INVALID;
Randall Spanglerd1836442010-06-10 09:59:04 -0700337 }
338
339 /* Success */
Randall Spangler83c88cf2010-06-11 16:14:18 -0700340 return VBOOT_SUCCESS;
Randall Spanglerd1836442010-06-10 09:59:04 -0700341}