blob: 083bbf273a52adb37c03f73a0ed97d9ac1858abf [file] [log] [blame]
Amit Blay6281ebc2015-01-11 14:44:08 +02001/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <debug.h>
30#include <dev/fbcon.h>
31#include <target.h>
32#include <mmc.h>
33#include <partition_parser.h>
34#include <platform.h>
35#include <crypto_hash.h>
36#include <malloc.h>
37#include <sha.h>
38#include <string.h>
39#include <rand.h>
40#include <stdlib.h>
41#include "scm.h"
42#include "mdtp.h"
43
44#define DIP_ENCRYPT 0
45#define DIP_DECRYPT 1
46
Amit Blaydf42d2f2015-02-03 16:37:09 +020047static int mdtp_tzbsp_dec_verify_DIP(DIP_t *enc_dip, DIP_t *dec_dip, uint32_t *verified);
48static int mdtp_tzbsp_enc_hash_DIP(DIP_t *dec_dip, DIP_t *enc_dip);
Amit Blay6281ebc2015-01-11 14:44:08 +020049
50/********************************************************************************/
51
52/* Read the DIP from EMMC */
Amit Blaydf42d2f2015-02-03 16:37:09 +020053static int read_DIP(DIP_t *dip)
Amit Blay6281ebc2015-01-11 14:44:08 +020054{
55 unsigned long long ptn = 0;
56 uint32_t actual_partition_size;
Amit Blaydf42d2f2015-02-03 16:37:09 +020057 uint32_t block_size = mmc_get_device_blocksize();
Amit Blay6281ebc2015-01-11 14:44:08 +020058
59 int index = INVALID_PTN;
60
61 ASSERT(dip != NULL);
62
63 index = partition_get_index("dip");
64 ptn = partition_get_offset(index);
65
66 if(ptn == 0)
67 {
68 return -1;
69 }
70
71 actual_partition_size = ROUNDUP(sizeof(DIP_t), block_size);
72
73 if(mmc_read(ptn, (void *)dip, actual_partition_size))
74 {
75 dprintf(CRITICAL, "mdtp: read_DIP: ERROR, cannot read DIP info\n");
76 return -1;
77 }
78
79 dprintf(INFO, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
80
81 return 0;
82}
83
84/* Store the DIP into the EMMC */
Amit Blaydf42d2f2015-02-03 16:37:09 +020085static int write_DIP(DIP_t *dip)
Amit Blay6281ebc2015-01-11 14:44:08 +020086{
87 unsigned long long ptn = 0;
88 uint32_t partition_size;
Amit Blaydf42d2f2015-02-03 16:37:09 +020089 uint32_t block_size = mmc_get_device_blocksize();
Amit Blay6281ebc2015-01-11 14:44:08 +020090
91 int index = INVALID_PTN;
92
93 ASSERT(dip != NULL);
94
95 index = partition_get_index("dip");
96 ptn = partition_get_offset(index);
97 if(ptn == 0)
98 {
99 return -1;
100 }
101
102 partition_size = partition_get_size(index);
103
104 if(partition_size < size)
105 {
106 dprintf(CRITICAL, "mdtp: write_DIP: ERROR, DIP partition too small\n");
107 return -1;
108 }
109
110 if(mmc_write(ptn, ROUNDUP(size, block_size), (void *)dip))
111 {
112 dprintf(CRITICAL, "mdtp: write_DIP: ERROR, cannot read DIP info\n");
113 return -1;
114 }
115
116 return 0;
117}
118
119/* Provision the DIP by storing the default DIP into the EMMC */
120static void provision_DIP()
121{
Amit Blaydf42d2f2015-02-03 16:37:09 +0200122 DIP_t *enc_dip;
123 DIP_t *dec_dip;
Amit Blay6281ebc2015-01-11 14:44:08 +0200124 int ret;
125
126 enc_dip = malloc(sizeof(DIP_t));
127 if (enc_dip == NULL)
128 {
129 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
130 return;
131 }
132
133 dec_dip = malloc(sizeof(DIP_t));
134 if (dec_dip == NULL)
135 {
136 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
137 free(enc_dip);
138 return;
139 }
140
141 memset(dec_dip, 0, sizeof(DIP_t));
142
143 dec_dip->status = DIP_STATUS_DEACTIVATED;
144
145 ret = mdtp_tzbsp_enc_hash_DIP(dec_dip, enc_dip);
146 if(ret < 0)
147 {
148 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot cipher DIP\n");
149 goto out;
150 }
151
152 ret = write_DIP(enc_dip);
153 if(ret < 0)
154 {
155 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot write DIP\n");
156 goto out;
157 }
158
159 ret = mdtp_tzbsp_set_provisioned_fuse();
160 if(ret < 0)
161 {
162 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot set DIP_PROVISIONED fuse\n\n");
163 goto out;
164 }
165
166out:
167 free(enc_dip);
168 free(dec_dip);
169}
170
171/* Validate a hash calculated on entire given partition */
Amit Blaydf42d2f2015-02-03 16:37:09 +0200172static int verify_partition_single_hash(char *name, uint32_t size, DIP_hash_table_entry_t *hash_table)
Amit Blay6281ebc2015-01-11 14:44:08 +0200173{
174 SHA256_CTX sha256_ctx;
175 unsigned char digest[32]={0};
176 unsigned long long ptn = 0;
177 int index = INVALID_PTN;
178 unsigned char *buf = (unsigned char *)target_get_scratch_address();
Amit Blaydf42d2f2015-02-03 16:37:09 +0200179 uint32_t block_size = mmc_get_device_blocksize();
Amit Blay6281ebc2015-01-11 14:44:08 +0200180 uint32_t actual_partition_size = ROUNDUP(size, block_size);
181
182 dprintf(INFO, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
183
184 ASSERT(name != NULL);
185 ASSERT(hash_table != NULL);
186
187 index = partition_get_index(name);
188 ptn = partition_get_offset(index);
189
190 if(ptn == 0) {
191 dprintf(CRITICAL, "mdtp: verify_partition_single_hash: %s: partition was not found\n", name);
192 return -1;
193 }
194
195 SHA256_Init(&sha256_ctx);
196
197 if (mmc_read(ptn, (void *)buf, actual_partition_size))
198 {
199 dprintf(CRITICAL, "mdtp: verify_partition__single_hash: %s: mmc_read() fail.\n", name);
200 return -1;
201 }
202
203 SHA256_Update(&sha256_ctx, buf, size);
204
205 SHA256_Final(digest, &sha256_ctx);
206
207 if (memcmp(digest, hash_table->hash, HASH_LEN))
208 {
209 dprintf(CRITICAL, "mdtp: verify_partition_single_hash: %s: Failed partition hash verification\n", name);
210
211 return -1;
212 }
213
214 dprintf(INFO, "verify_partition_single_hash: %s: VERIFIED!\n", name);
215
216 return 0;
217}
218
219/* Validate a hash table calculated per block of a given partition */
Amit Blaydf42d2f2015-02-03 16:37:09 +0200220static int verify_partition_block_hash(char *name,
Amit Blay6281ebc2015-01-11 14:44:08 +0200221 uint32_t size,
222 uint32_t total_num_blocks,
223 uint32_t verify_num_blocks,
Amit Blaydf42d2f2015-02-03 16:37:09 +0200224 DIP_hash_table_entry_t *hash_table,
Amit Blay6281ebc2015-01-11 14:44:08 +0200225 uint8_t *force_verify_block)
226{
227 SHA256_CTX sha256_ctx;
228 unsigned char digest[32]={0};
229 unsigned long long ptn = 0;
230 int index = INVALID_PTN;
231 unsigned char *buf = (unsigned char *)target_get_scratch_address();
232 uint32_t bytes_to_read;
233 uint32_t block_num = 0;
234
235 dprintf(INFO, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
236
237 ASSERT(name != NULL);
238 ASSERT(hash_table != NULL);
239
240 index = partition_get_index(name);
241 ptn = partition_get_offset(index);
242
243 if(ptn == 0) {
244 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: partition was not found\n", name);
245 return -1;
246 }
247
248 while (MDTP_FWLOCK_BLOCK_SIZE * block_num < size)
249 {
250 if (*force_verify_block == 0)
251 {
252 /* Skip validation of this block with probability of verify_num_blocks / total_num_blocks */
253 if ((rand() % total_num_blocks) >= verify_num_blocks)
254 {
255 block_num++;
256 hash_table += 1;
257 force_verify_block += 1;
258 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: skipped verification of block %d\n", name, block_num);
259 continue;
260 }
261 }
262
263 SHA256_Init(&sha256_ctx);
264
265 if ((size - (MDTP_FWLOCK_BLOCK_SIZE * block_num) < MDTP_FWLOCK_BLOCK_SIZE))
266 {
267 bytes_to_read = size - (MDTP_FWLOCK_BLOCK_SIZE * block_num);
268 } else
269 {
270 bytes_to_read = MDTP_FWLOCK_BLOCK_SIZE;
271 }
272
273 if (mmc_read(ptn + (MDTP_FWLOCK_BLOCK_SIZE * block_num), (void *)buf, bytes_to_read))
274 {
275 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: mmc_read() fail.\n", name);
276 return -1;
277 }
278
279 SHA256_Update(&sha256_ctx, buf, bytes_to_read);
280 SHA256_Update(&sha256_ctx, &block_num, sizeof(block_num));
281
282 SHA256_Final(digest, &sha256_ctx);
283
284 if (memcmp(digest, hash_table->hash, HASH_LEN))
285 {
286 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: Failed partition hash[%d] verification\n", name, block_num);
287 return -1;
288 }
289
290 block_num++;
291 hash_table += 1;
292 force_verify_block += 1;
293 }
294
295 dprintf(INFO, "verify_partition_block_hash: %s: VERIFIED!\n", name);
296
297 return 0;
298}
299
300/* Verify a given partitinon */
Amit Blaydf42d2f2015-02-03 16:37:09 +0200301static int verify_partition(char *name,
Amit Blay6281ebc2015-01-11 14:44:08 +0200302 uint32_t size,
303 mdtp_fwlock_mode_t hash_mode,
304 uint32_t total_num_blocks,
305 uint32_t verify_num_blocks,
306 DIP_hash_table_entry_t *hash_table,
307 uint8_t *force_verify_block)
308{
309
310 ASSERT(name != NULL);
311 ASSERT(hash_table != NULL);
312
313 if (hash_mode == MDTP_FWLOCK_MODE_SINGLE)
314 {
315 return verify_partition_single_hash(name, size, hash_table);
316 } else if (hash_mode == MDTP_FWLOCK_MODE_BLOCK || hash_mode == MDTP_FWLOCK_MODE_FILES)
317 {
318 return verify_partition_block_hash(name, size, total_num_blocks, verify_num_blocks, hash_table, force_verify_block);
319 }
320 else
321 {
322 dprintf(CRITICAL, "mdtp: verify_partition: %s: Wrong DIP partition hash mode\n", name);
323 return -1;
324 }
325
326 return 0;
327}
328
329/* Verify all protected partitinons according to the DIP */
330static int verify_all_partitions(DIP_t *dip, verify_result_t *verify_result)
331{
332 int i;
333 int verify_failure = 0;
334 uint32_t total_num_blocks;
335
336 ASSERT(dip != NULL);
337 ASSERT(verify_result != NULL);
338
339 *verify_result = VERIFY_FAILED;
340
341 if (dip->status == DIP_STATUS_DEACTIVATED)
342 {
343 *verify_result = VERIFY_SKIPPED;
344 return 0;
345 }
346 else if (dip->status == DIP_STATUS_ACTIVATED)
347 {
348 show_checking_msg();
349
350 for(i=0; i<MAX_PARTITIONS; i++)
351 {
352 if(dip->partition_cfg[i].lock_enabled && dip->partition_cfg[i].size)
353 {
354 total_num_blocks = ((dip->partition_cfg[i].size - 1) / MDTP_FWLOCK_BLOCK_SIZE);
355
356 verify_failure |= verify_partition(dip->partition_cfg[i].name,
357 dip->partition_cfg[i].size,
358 dip->partition_cfg[i].hash_mode,
359 total_num_blocks,
360 (dip->partition_cfg[i].verify_ratio * total_num_blocks) / 100,
361 dip->partition_cfg[i].hash_table,
362 dip->partition_cfg[i].force_verify_block);
363 }
364 }
365
366 if (verify_failure)
367 {
368 dprintf(CRITICAL, "mdtp: verify_all_partitions: Failed partition verification\n");
369 show_invalid_msg();
370 return -1;
371 }
372
373 }
374
375 *verify_result = VERIFY_OK;
376 show_OK_msg();
377 return 0;
378}
379
380/* Verify the DIP and all protected partitions */
381static void validate_DIP_and_firmware()
382{
383 int ret;
Amit Blaydf42d2f2015-02-03 16:37:09 +0200384 DIP_t *enc_dip;
385 DIP_t *dec_dip;
Amit Blay6281ebc2015-01-11 14:44:08 +0200386 uint32_t verified = 0;
387 verify_result_t verify_result;
Amit Blaydf42d2f2015-02-03 16:37:09 +0200388 uint32_t block_size = mmc_get_device_blocksize();
Amit Blay6281ebc2015-01-11 14:44:08 +0200389
390 enc_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
391 if (enc_dip == NULL)
392 {
393 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
394 return;
395 }
396
397 dec_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
398 if (dec_dip == NULL)
399 {
400 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
401 free(enc_dip);
402 return;
403 }
404
405 /* Read the DIP holding the MDTP Firmware Lock state from the DIP partition */
406 ret = read_DIP(enc_dip);
407 if(ret < 0)
408 {
409 dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot read DIP\n");
410 goto out;
411 }
412
413 /* Decrypt and verify the integrity of the DIP */
414 ret = mdtp_tzbsp_dec_verify_DIP(enc_dip, dec_dip, &verified);
415 if(ret < 0)
416 {
417 dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot verify DIP\n");
418 show_invalid_msg();
419 goto out;
420 }
421
422 /* In case DIP integrity verification fails, notify the user and halt */
423 if(!verified)
424 {
425 dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted DIP\n");
426 show_invalid_msg();
427 goto out;
428 }
429
430 /* Verify the integrity of the partitions which are protectedm, according to the content of the DIP */
431 ret = verify_all_partitions(dec_dip, &verify_result);
432 if(ret < 0)
433 {
434 dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot verify firmware\n");
435 goto out;
436 }
437
438 if (verify_result == VERIFY_OK)
439 {
440 dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify OK\n");
441 }
442 else if (verify_result == VERIFY_FAILED)
443 {
444 dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted firmware\n");
445 } else /* VERIFY_SKIPPED */
446 {
447 dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify skipped\n");
448 }
449
450out:
451 free(enc_dip);
452 free(dec_dip);
453
454 return;
455}
456
457/********************************************************************************/
458
459/** Entry point of the MDTP Firmware Lock: If needed, verify the DIP
460 * and all protected partitions **/
461
462int mdtp_fwlock_verify_lock()
463{
Amit Blaydf42d2f2015-02-03 16:37:09 +0200464 int ret;
465 bool enabled;
Amit Blay6281ebc2015-01-11 14:44:08 +0200466
Amit Blaydf42d2f2015-02-03 16:37:09 +0200467 ret = mdtp_fuse_get_enabled(&enabled);
468 if(ret)
Amit Blay6281ebc2015-01-11 14:44:08 +0200469 {
Amit Blaydf42d2f2015-02-03 16:37:09 +0200470 dprintf(CRITICAL, "mdtp: mdtp_fwlock_verify_lock: ERROR, cannot get enabled fuse\n");
Amit Blay6281ebc2015-01-11 14:44:08 +0200471 return -1;
472 }
473
Amit Blaydf42d2f2015-02-03 16:37:09 +0200474 /* Continue with Firmware Lock verification only if enabled by eFuse */
475 if (enabled)
Amit Blay6281ebc2015-01-11 14:44:08 +0200476 {
477 validate_DIP_and_firmware();
478 }
479
480 return 0;
481}
482
483/********************************************************************************/
484
Amit Blay6281ebc2015-01-11 14:44:08 +0200485/* Decrypt a given DIP and verify its integrity */
Amit Blaydf42d2f2015-02-03 16:37:09 +0200486static int mdtp_tzbsp_dec_verify_DIP(DIP_t *enc_dip, DIP_t *dec_dip, uint32_t *verified)
Amit Blay6281ebc2015-01-11 14:44:08 +0200487{
Amit Blaydf42d2f2015-02-03 16:37:09 +0200488 unsigned char *hash_p;
Amit Blay6281ebc2015-01-11 14:44:08 +0200489 unsigned char hash[HASH_LEN];
490 SHA256_CTX sha256_ctx;
491 int ret;
492
493 ASSERT(enc_dip != NULL);
494 ASSERT(dec_dip != NULL);
495 ASSERT(verified != NULL);
496
497 ret = mdtp_cipher_dip_cmd((uint8_t*)enc_dip, sizeof(DIP_t),
498 (uint8_t*)dec_dip, sizeof(DIP_t),
499 DIP_DECRYPT);
500 if (ret)
501 {
502 dprintf(CRITICAL, "mdtp: mdtp_tzbsp_dec_verify_DIP: ERROR, cannot cipher DIP\n");
503 *verified = 0;
504 return -1;
505 }
506
507 SHA256_Init(&sha256_ctx);
508 SHA256_Update(&sha256_ctx, dec_dip, sizeof(DIP_t) - HASH_LEN);
509 SHA256_Final(hash, &sha256_ctx);
510
511 hash_p = (unsigned char*)dec_dip + sizeof(DIP_t) - HASH_LEN;
512
513 if (memcmp(hash, hash_p, HASH_LEN))
514 {
515 *verified = 0;
516 }
517 else
518 {
519 *verified = 1;
520 }
521
522 return 0;
523}
524
Amit Blaydf42d2f2015-02-03 16:37:09 +0200525static int mdtp_tzbsp_enc_hash_DIP(DIP_t *dec_dip, DIP_t *enc_dip)
Amit Blay6281ebc2015-01-11 14:44:08 +0200526{
Amit Blaydf42d2f2015-02-03 16:37:09 +0200527 unsigned char *hash_p;
Amit Blay6281ebc2015-01-11 14:44:08 +0200528 SHA256_CTX sha256_ctx;
529 int ret;
530
531 ASSERT(dec_dip != NULL);
532 ASSERT(enc_dip != NULL);
533
534 hash_p = (unsigned char*)dec_dip + sizeof(DIP_t) - HASH_LEN;
535
536 SHA256_Init(&sha256_ctx);
537 SHA256_Update(&sha256_ctx, dec_dip, sizeof(DIP_t) - HASH_LEN);
538 SHA256_Final(hash_p, &sha256_ctx);
539
540 ret = mdtp_cipher_dip_cmd((uint8_t*)dec_dip, sizeof(DIP_t),
541 (uint8_t*)enc_dip, sizeof(DIP_t),
542 DIP_ENCRYPT);
543 if (ret)
544 {
545 dprintf(CRITICAL, "mdtp: mdtp_tzbsp_enc_hash_DIP: ERROR, cannot cipher DIP\n");
546 return -1;
547 }
548
549 return 0;
550}