blob: 7e12dfa4c5eaa7bf60196220ba6a5759219ea52c [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
47static int mdtp_tzbsp_get_provisioned_fuse();
48static int mdtp_tzbsp_set_provisioned_fuse();
49static int mdtp_tzbsp_dec_verify_DIP(DIP_t* enc_dip, DIP_t* dec_dip, uint32_t *verified);
50static int mdtp_tzbsp_enc_hash_DIP(DIP_t* dec_dip, DIP_t* enc_dip);
51
52unsigned block_size = 0;
53
54/********************************************************************************/
55
56/* Read the DIP from EMMC */
57static int read_DIP(DIP_t* dip)
58{
59 unsigned long long ptn = 0;
60 uint32_t actual_partition_size;
61
62 int index = INVALID_PTN;
63
64 ASSERT(dip != NULL);
65
66 index = partition_get_index("dip");
67 ptn = partition_get_offset(index);
68
69 if(ptn == 0)
70 {
71 return -1;
72 }
73
74 actual_partition_size = ROUNDUP(sizeof(DIP_t), block_size);
75
76 if(mmc_read(ptn, (void *)dip, actual_partition_size))
77 {
78 dprintf(CRITICAL, "mdtp: read_DIP: ERROR, cannot read DIP info\n");
79 return -1;
80 }
81
82 dprintf(INFO, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
83
84 return 0;
85}
86
87/* Store the DIP into the EMMC */
88static int write_DIP(DIP_t* dip)
89{
90 unsigned long long ptn = 0;
91 uint32_t partition_size;
92
93 int index = INVALID_PTN;
94
95 ASSERT(dip != NULL);
96
97 index = partition_get_index("dip");
98 ptn = partition_get_offset(index);
99 if(ptn == 0)
100 {
101 return -1;
102 }
103
104 partition_size = partition_get_size(index);
105
106 if(partition_size < size)
107 {
108 dprintf(CRITICAL, "mdtp: write_DIP: ERROR, DIP partition too small\n");
109 return -1;
110 }
111
112 if(mmc_write(ptn, ROUNDUP(size, block_size), (void *)dip))
113 {
114 dprintf(CRITICAL, "mdtp: write_DIP: ERROR, cannot read DIP info\n");
115 return -1;
116 }
117
118 return 0;
119}
120
121/* Provision the DIP by storing the default DIP into the EMMC */
122static void provision_DIP()
123{
124 DIP_t* enc_dip;
125 DIP_t* dec_dip;
126 int ret;
127
128 enc_dip = malloc(sizeof(DIP_t));
129 if (enc_dip == NULL)
130 {
131 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
132 return;
133 }
134
135 dec_dip = malloc(sizeof(DIP_t));
136 if (dec_dip == NULL)
137 {
138 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
139 free(enc_dip);
140 return;
141 }
142
143 memset(dec_dip, 0, sizeof(DIP_t));
144
145 dec_dip->status = DIP_STATUS_DEACTIVATED;
146
147 ret = mdtp_tzbsp_enc_hash_DIP(dec_dip, enc_dip);
148 if(ret < 0)
149 {
150 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot cipher DIP\n");
151 goto out;
152 }
153
154 ret = write_DIP(enc_dip);
155 if(ret < 0)
156 {
157 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot write DIP\n");
158 goto out;
159 }
160
161 ret = mdtp_tzbsp_set_provisioned_fuse();
162 if(ret < 0)
163 {
164 dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot set DIP_PROVISIONED fuse\n\n");
165 goto out;
166 }
167
168out:
169 free(enc_dip);
170 free(dec_dip);
171}
172
173/* Validate a hash calculated on entire given partition */
174static int verify_partition_single_hash(char* name, uint32_t size, DIP_hash_table_entry_t* hash_table)
175{
176 SHA256_CTX sha256_ctx;
177 unsigned char digest[32]={0};
178 unsigned long long ptn = 0;
179 int index = INVALID_PTN;
180 unsigned char *buf = (unsigned char *)target_get_scratch_address();
181 uint32_t actual_partition_size = ROUNDUP(size, block_size);
182
183 dprintf(INFO, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
184
185 ASSERT(name != NULL);
186 ASSERT(hash_table != NULL);
187
188 index = partition_get_index(name);
189 ptn = partition_get_offset(index);
190
191 if(ptn == 0) {
192 dprintf(CRITICAL, "mdtp: verify_partition_single_hash: %s: partition was not found\n", name);
193 return -1;
194 }
195
196 SHA256_Init(&sha256_ctx);
197
198 if (mmc_read(ptn, (void *)buf, actual_partition_size))
199 {
200 dprintf(CRITICAL, "mdtp: verify_partition__single_hash: %s: mmc_read() fail.\n", name);
201 return -1;
202 }
203
204 SHA256_Update(&sha256_ctx, buf, size);
205
206 SHA256_Final(digest, &sha256_ctx);
207
208 if (memcmp(digest, hash_table->hash, HASH_LEN))
209 {
210 dprintf(CRITICAL, "mdtp: verify_partition_single_hash: %s: Failed partition hash verification\n", name);
211
212 return -1;
213 }
214
215 dprintf(INFO, "verify_partition_single_hash: %s: VERIFIED!\n", name);
216
217 return 0;
218}
219
220/* Validate a hash table calculated per block of a given partition */
221static int verify_partition_block_hash(char* name,
222 uint32_t size,
223 uint32_t total_num_blocks,
224 uint32_t verify_num_blocks,
225 DIP_hash_table_entry_t* hash_table,
226 uint8_t *force_verify_block)
227{
228 SHA256_CTX sha256_ctx;
229 unsigned char digest[32]={0};
230 unsigned long long ptn = 0;
231 int index = INVALID_PTN;
232 unsigned char *buf = (unsigned char *)target_get_scratch_address();
233 uint32_t bytes_to_read;
234 uint32_t block_num = 0;
235
236 dprintf(INFO, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
237
238 ASSERT(name != NULL);
239 ASSERT(hash_table != NULL);
240
241 index = partition_get_index(name);
242 ptn = partition_get_offset(index);
243
244 if(ptn == 0) {
245 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: partition was not found\n", name);
246 return -1;
247 }
248
249 while (MDTP_FWLOCK_BLOCK_SIZE * block_num < size)
250 {
251 if (*force_verify_block == 0)
252 {
253 /* Skip validation of this block with probability of verify_num_blocks / total_num_blocks */
254 if ((rand() % total_num_blocks) >= verify_num_blocks)
255 {
256 block_num++;
257 hash_table += 1;
258 force_verify_block += 1;
259 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: skipped verification of block %d\n", name, block_num);
260 continue;
261 }
262 }
263
264 SHA256_Init(&sha256_ctx);
265
266 if ((size - (MDTP_FWLOCK_BLOCK_SIZE * block_num) < MDTP_FWLOCK_BLOCK_SIZE))
267 {
268 bytes_to_read = size - (MDTP_FWLOCK_BLOCK_SIZE * block_num);
269 } else
270 {
271 bytes_to_read = MDTP_FWLOCK_BLOCK_SIZE;
272 }
273
274 if (mmc_read(ptn + (MDTP_FWLOCK_BLOCK_SIZE * block_num), (void *)buf, bytes_to_read))
275 {
276 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: mmc_read() fail.\n", name);
277 return -1;
278 }
279
280 SHA256_Update(&sha256_ctx, buf, bytes_to_read);
281 SHA256_Update(&sha256_ctx, &block_num, sizeof(block_num));
282
283 SHA256_Final(digest, &sha256_ctx);
284
285 if (memcmp(digest, hash_table->hash, HASH_LEN))
286 {
287 dprintf(CRITICAL, "mdtp: verify_partition_block_hash: %s: Failed partition hash[%d] verification\n", name, block_num);
288 return -1;
289 }
290
291 block_num++;
292 hash_table += 1;
293 force_verify_block += 1;
294 }
295
296 dprintf(INFO, "verify_partition_block_hash: %s: VERIFIED!\n", name);
297
298 return 0;
299}
300
301/* Verify a given partitinon */
302static int verify_partition(char* name,
303 uint32_t size,
304 mdtp_fwlock_mode_t hash_mode,
305 uint32_t total_num_blocks,
306 uint32_t verify_num_blocks,
307 DIP_hash_table_entry_t *hash_table,
308 uint8_t *force_verify_block)
309{
310
311 ASSERT(name != NULL);
312 ASSERT(hash_table != NULL);
313
314 if (hash_mode == MDTP_FWLOCK_MODE_SINGLE)
315 {
316 return verify_partition_single_hash(name, size, hash_table);
317 } else if (hash_mode == MDTP_FWLOCK_MODE_BLOCK || hash_mode == MDTP_FWLOCK_MODE_FILES)
318 {
319 return verify_partition_block_hash(name, size, total_num_blocks, verify_num_blocks, hash_table, force_verify_block);
320 }
321 else
322 {
323 dprintf(CRITICAL, "mdtp: verify_partition: %s: Wrong DIP partition hash mode\n", name);
324 return -1;
325 }
326
327 return 0;
328}
329
330/* Verify all protected partitinons according to the DIP */
331static int verify_all_partitions(DIP_t *dip, verify_result_t *verify_result)
332{
333 int i;
334 int verify_failure = 0;
335 uint32_t total_num_blocks;
336
337 ASSERT(dip != NULL);
338 ASSERT(verify_result != NULL);
339
340 *verify_result = VERIFY_FAILED;
341
342 if (dip->status == DIP_STATUS_DEACTIVATED)
343 {
344 *verify_result = VERIFY_SKIPPED;
345 return 0;
346 }
347 else if (dip->status == DIP_STATUS_ACTIVATED)
348 {
349 show_checking_msg();
350
351 for(i=0; i<MAX_PARTITIONS; i++)
352 {
353 if(dip->partition_cfg[i].lock_enabled && dip->partition_cfg[i].size)
354 {
355 total_num_blocks = ((dip->partition_cfg[i].size - 1) / MDTP_FWLOCK_BLOCK_SIZE);
356
357 verify_failure |= verify_partition(dip->partition_cfg[i].name,
358 dip->partition_cfg[i].size,
359 dip->partition_cfg[i].hash_mode,
360 total_num_blocks,
361 (dip->partition_cfg[i].verify_ratio * total_num_blocks) / 100,
362 dip->partition_cfg[i].hash_table,
363 dip->partition_cfg[i].force_verify_block);
364 }
365 }
366
367 if (verify_failure)
368 {
369 dprintf(CRITICAL, "mdtp: verify_all_partitions: Failed partition verification\n");
370 show_invalid_msg();
371 return -1;
372 }
373
374 }
375
376 *verify_result = VERIFY_OK;
377 show_OK_msg();
378 return 0;
379}
380
381/* Verify the DIP and all protected partitions */
382static void validate_DIP_and_firmware()
383{
384 int ret;
385 DIP_t* enc_dip;
386 DIP_t* dec_dip;
387 uint32_t verified = 0;
388 verify_result_t verify_result;
389
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{
464 int provisioned_fuse;
465
466 block_size = mmc_get_device_blocksize();
467
468 provisioned_fuse = mdtp_tzbsp_get_provisioned_fuse();
469 if(provisioned_fuse < 0)
470 {
471 dprintf(CRITICAL, "mdtp: mdtp_fwlock_verify_lock: ERROR, cannot get DIP_PROVISIONED fuse\n");
472 return -1;
473 }
474
475 if (!provisioned_fuse)
476 {
477 provision_DIP();
478 }
479 else
480 {
481 validate_DIP_and_firmware();
482 }
483
484 return 0;
485}
486
487/********************************************************************************/
488
489/* Functions communicating with TZBSP */
490
491static int mdtp_tzbsp_get_provisioned_fuse()
492{
493 return 1;
494}
495
496static int mdtp_tzbsp_set_provisioned_fuse()
497{
498 return 0;
499}
500
501/* Decrypt a given DIP and verify its integrity */
502static int mdtp_tzbsp_dec_verify_DIP(DIP_t* enc_dip, DIP_t* dec_dip, uint32_t *verified)
503{
504 unsigned char* hash_p;
505 unsigned char hash[HASH_LEN];
506 SHA256_CTX sha256_ctx;
507 int ret;
508
509 ASSERT(enc_dip != NULL);
510 ASSERT(dec_dip != NULL);
511 ASSERT(verified != NULL);
512
513 ret = mdtp_cipher_dip_cmd((uint8_t*)enc_dip, sizeof(DIP_t),
514 (uint8_t*)dec_dip, sizeof(DIP_t),
515 DIP_DECRYPT);
516 if (ret)
517 {
518 dprintf(CRITICAL, "mdtp: mdtp_tzbsp_dec_verify_DIP: ERROR, cannot cipher DIP\n");
519 *verified = 0;
520 return -1;
521 }
522
523 SHA256_Init(&sha256_ctx);
524 SHA256_Update(&sha256_ctx, dec_dip, sizeof(DIP_t) - HASH_LEN);
525 SHA256_Final(hash, &sha256_ctx);
526
527 hash_p = (unsigned char*)dec_dip + sizeof(DIP_t) - HASH_LEN;
528
529 if (memcmp(hash, hash_p, HASH_LEN))
530 {
531 *verified = 0;
532 }
533 else
534 {
535 *verified = 1;
536 }
537
538 return 0;
539}
540
541static int mdtp_tzbsp_enc_hash_DIP(DIP_t* dec_dip, DIP_t* enc_dip)
542{
543 unsigned char* hash_p;
544 SHA256_CTX sha256_ctx;
545 int ret;
546
547 ASSERT(dec_dip != NULL);
548 ASSERT(enc_dip != NULL);
549
550 hash_p = (unsigned char*)dec_dip + sizeof(DIP_t) - HASH_LEN;
551
552 SHA256_Init(&sha256_ctx);
553 SHA256_Update(&sha256_ctx, dec_dip, sizeof(DIP_t) - HASH_LEN);
554 SHA256_Final(hash_p, &sha256_ctx);
555
556 ret = mdtp_cipher_dip_cmd((uint8_t*)dec_dip, sizeof(DIP_t),
557 (uint8_t*)enc_dip, sizeof(DIP_t),
558 DIP_ENCRYPT);
559 if (ret)
560 {
561 dprintf(CRITICAL, "mdtp: mdtp_tzbsp_enc_hash_DIP: ERROR, cannot cipher DIP\n");
562 return -1;
563 }
564
565 return 0;
566}