tizen 2.4 release
[kernel/u-boot-tm1.git] / property / secure_verify.c
1 #include <config.h>
2 #include <common.h>
3 #include <asm/arch/sci_types.h>
4 #include "secure_verify.h"
5
6 #ifdef  CONFIG_EMMC_BOOT
7 #else
8 #include <nand.h>
9 #endif
10
11 #define SHA1_SUM_LEN    20
12
13 LOCAL __inline char *_w2c(wchar_t * wchar)
14 {
15         static char buf[73] = { 0 };
16         unsigned int i = 0;
17         while ((NULL != wchar[i]) && (i < 72)) {
18                 buf[i] = wchar[i] & 0xFF;
19                 i++;
20         }
21         buf[i] = 0;
22
23         return buf;
24 }
25
26 /*
27 void hexdump(const char *title, const unsigned char *s, int l)
28 {
29     int n=0;
30
31     printf("%s",title);
32     for( ; n < l ; ++n)
33     {
34         if((n%16) == 0)
35             printf("\n%04x",n);
36         printf(" %02x",s[n]);
37     }
38     printf("\n");
39 }
40 */
41
42 unsigned char sec_header[SEC_HEADER_MAX_SIZE];
43
44 int secure_header_parser(uint8_t * header_addr)
45 {
46         if (strcmp(header_addr, HEADER_NAME) == 0)
47                 return 1;
48         else
49                 return 0;
50 }
51
52 int get_code_addr(wchar_t * name, uint8_t * header_addr)
53 {
54         int addr = 0;
55         int i = 0;
56         header_info_t *header_p = (header_info_t *) header_addr;
57
58         printf("%s, name: %s enter\r\n", __FUNCTION__, _w2c(name));
59         if (name && wcscmp(L"splloader0", name) == 0) {
60 #ifdef CONFIG_ROM_VERIFY_SPL
61                 addr = header_addr + CONFIG_BOOTINFO_LENGTH * 2;
62 #else
63                 addr = header_addr + CONFIG_SPL_HASH_LEN;
64 #endif
65                 return addr;
66         }
67
68         for (i = 0; i < header_p->tags_number; i++) {
69                 if (header_p->tag[i].tag_name == CODE_NAME) {
70                         addr = header_addr + (header_p->tag[i].tag_offset) * MIN_UNIT;
71                         break;
72                 }
73         }
74 #ifdef CONFIG_ROM_VERIFY_SPL
75         if (wcscmp(L"splloader", name) == 0) {
76                 addr -= CONFIG_BOOTINFO_LENGTH;
77         }
78 #endif
79         return addr;
80 }
81
82 uint32_t get_code_offset(uint8_t * header_addr)
83 {
84         int i = 0;
85         header_info_t *header_p = (header_info_t *) header_addr;
86
87         for (i = 0; i < header_p->tags_number; i++) {
88                 if (header_p->tag[i].tag_name == CODE_NAME) {
89                         return header_p->tag[i].tag_offset;
90                 }
91         }
92         return 0;
93 }
94
95 int get_vlr_addr(wchar_t * name, uint8_t * header_addr)
96 {
97         int i = 0;
98         int addr = 0;
99         header_info_t *header_p = (header_info_t *) header_addr;
100
101         printf("%s, name: %s enter\r\n", __FUNCTION__, _w2c(name));
102         if (name) {
103                 if (wcscmp(L"splloader0", name) == 0) {
104                         addr = header_addr + CONFIG_SPL_LOAD_LEN - VLR_INFO_SIZ;
105                         return addr;
106                 }
107         }
108
109         for (i = 0; i < header_p->tags_number; i++) {
110                 if (header_p->tag[i].tag_name == VLR_NAME) {
111                         addr = header_addr + (header_p->tag[i].tag_offset) * MIN_UNIT;
112                         break;
113                 }
114         }
115         return addr;
116 }
117
118 int get_puk_addr(wchar_t * name, uint8_t * header_addr)
119 {
120         int addr = 0;
121         int i = 0;
122         int size;
123         header_info_t *header_p = (header_info_t *) header_addr;
124
125         printf("%s, name: %s enter\r\n", __FUNCTION__, _w2c(name));
126         if (name) {
127                 if (wcscmp(L"splloader0", name) == 0) {
128 #ifdef CONFIG_ROM_VERIFY_SPL
129                         addr = header_addr + CONFIG_BOOTINFO_LENGTH;
130 #else
131                         addr = header_addr + CONFIG_SPL_HASH_LEN - KEY_INFO_SIZ;
132 #endif
133                         return addr;
134                 } else if (wcscmp(L"splloader", name) == 0) {
135                         size = SEC_HEADER_MAX_SIZE;
136 #ifdef  CONFIG_EMMC_BOOT
137                         if (TRUE != Emmc_Read(1 /* PARTITION_BOOT1 */ , PUBKEY_BSC_BLOCK_INDEX,
138                                               PUBKEY_READ_BLOCK_NUMS, (uint8 *) sec_header)) {
139                                 printf("PARTITION_BOOT1 read error \n");
140                                 return 0;
141                         }
142 #else
143                         if (nand_read_skip_bad(&nand_info[0], 0, &size, (uint8 *) sec_header) != 0) {
144                                 printf("PARTITION_BOOT1 read error \n");
145                                 return 0;
146                         }
147 #endif
148 #ifdef CONFIG_ROM_VERIFY_SPL
149                         addr = sec_header;
150 #else
151                         addr = sec_header + CONFIG_SPL_HASH_LEN - KEY_INFO_SIZ;
152 #endif
153                         return addr;
154                 } else if (wcscmp(L"uboot", name) == 0) {
155                         size = SEC_HEADER_MAX_SIZE;
156 #ifdef  CONFIG_EMMC_BOOT
157                         if (TRUE != Emmc_Read(2 /* PARTITION_BOOT2 */ , PUBKEY_VLR_BLOCK_INDEX,
158                                               PUBKEY_READ_BLOCK_NUMS, (uint8 *) sec_header)) {
159                                 printf("PARTITION_BOOT2 read error \n");
160                                 return 0;
161                         }
162 #else
163                         if (nand_read_skip_bad(&nand_info[0], CONFIG_SYS_NAND_U_BOOT_OFFS, &size, (uint8 *) sec_header) != 0) {
164                                 printf("PARTITION_BOOT2 read error \n");
165                                 return 0;
166                         }
167 #endif
168 #ifdef CONFIG_ROM_VERIFY_SPL
169                         addr = sec_header;
170                         return addr;
171 #endif
172                         header_p = (header_info_t *) sec_header;
173                 } else if (wcscmp(L"fdl2", name) == 0) {
174                         header_p = (header_info_t *) CONFIG_SYS_SDRAM_BASE;
175                 } else {
176                         //no operation
177                 }
178         }
179
180         for (i = 0; i < header_p->tags_number; i++) {
181                 if (header_p->tag[i].tag_name == PUK_NAME) {
182                         addr = (uint8_t *) header_p + (header_p->tag[i].tag_offset) * MIN_UNIT;
183                         break;
184                 }
185         }
186         return addr;
187 }
188
189 /*copy form libefuse*/
190 #define UID_BLOCK_START                 0
191 #define UID_BLOCK_END                   1
192 #define UID_BLOCK_LEN                  (UID_BLOCK_END - UID_BLOCK_START + 1)
193 #define HASH_BLOCK_START                2
194 #define HASH_BLOCK_END                  6
195 #define HASH_BLOCK_LEN                  (HASH_BLOCK_END - HASH_BLOCK_START + 1)
196 #define SECURE_BOOT_BLOCK               1
197 #define SECURE_BOOT_BIT                 18
198 //#define MIN(a, b)
199
200 int HexChar2Dec(unsigned char c)
201 {
202         if ('0' <= c && c <= '9') {
203                 return (int)(c - '0');
204         } else if ('a' <= c && c <= 'f') {
205                 return ((int)(c - 'a') + 10);
206         } else if ('A' <= c && c <= 'F') {
207                 return ((int)(c - 'A') + 10);
208         } else {
209                 return -1;
210         }
211 }
212
213 int str2Num16(const unsigned char *str)
214 {
215         return (str[1] == '\0') ? HexChar2Dec(str[0]) : HexChar2Dec(str[0]) * 16 + HexChar2Dec(str[1]);
216 }
217
218 void convertToLittleEndian(unsigned int *data)
219 {
220         *data = ((*data & 0xff000000) >> 24)
221             | ((*data & 0x00ff0000) >> 8)
222             | ((*data & 0x0000ff00) << 8)
223             | ((*data & 0x000000ff) << 24);
224 }
225
226 int efuse_hash_read(unsigned char *hash, int count)
227 {
228         unsigned char buf[HASH_BLOCK_LEN * 8 + 1] = { 0 };
229         unsigned int values[HASH_BLOCK_LEN] = { 0 };
230         int i = 0, len = 0, ret = -1;
231         unsigned char *ptr = hash;
232         int idx;
233 //      printf("%s()->Line:%d; count = %d \n", __FUNCTION__, __LINE__, count);
234
235         if ((0 == hash) || (count < 1))
236                 return -1;
237
238         len = MIN(count, sizeof(buf));
239         for (i = HASH_BLOCK_START; i <= HASH_BLOCK_END; i++) {
240                 //ret = efuse_read(i, &values[i - HASH_BLOCK_START]);
241 //              ret = sci_efuse_read(i);
242                 ret = __ddie_efuse_read(i);
243                 values[i - HASH_BLOCK_START] = ret;
244                 convertToLittleEndian(&values[i - HASH_BLOCK_START]);
245                 if (ret == 0) {
246                         printf("efuse read err\n");
247                         return -2;
248                 }
249         }
250
251         for (i = 0; i < HASH_BLOCK_LEN; i++) {
252                 sprintf((char *)&buf[i * 8], "%08x", values[i]);
253         }
254
255         len = (strlen(buf) % 2 == 0) ? strlen(buf) / 2 : (strlen(buf) / 2 + 1);
256
257         for (i = 0; i < len; ++i) {
258                 idx = i * 2;
259                 *ptr++ = str2Num16(buf + idx);
260         }
261
262         //strncpy((char *)hash, (char *)&buf, len);
263         //printf("%s()->Line:%d; hash = %s, len = %d \n", __FUNCTION__, __LINE__, hash, len-1);
264         return (len - 1);
265 }
266
267 void secure_hash_str2ul(void *dst, void *src, unsigned int count)
268 {
269         int i;
270         unsigned char tmp[9] = { 0 };
271         unsigned char buf[HASH_BLOCK_LEN * 8 + 1] = { 0 };
272         unsigned int *pintdst = dst;
273
274         sprintf(buf, "%08x%08x%08x%08x%08x", *(uint32_t *) src, *(uint32_t *) (src + 4), *(uint32_t *) (src + 8), *(uint32_t *) (src + 12),
275                 *(uint32_t *) (src + 16));
276         buf[40] = '\0';
277         for (i = 0; i < count; i += 8) {
278                 memset(tmp, 0, sizeof(tmp));
279                 strncpy((char *)tmp, (char *)&buf[i], 8);
280                 tmp[8] = '\0';
281                 *pintdst++ = (unsigned int)simple_strtoul(tmp, 0, 16);
282         }
283
284 }
285
286 int secure_verify(wchar_t * name, uint8_t * header, uint8_t * code)
287 {
288         int vlr_addr;
289         int puk_addr;
290         int code_addr;
291         unsigned char rom_efuse_hash[SHA1_SUM_LEN] = { 0 };
292         unsigned char cal_efuse_hash[SHA1_SUM_LEN] = { 0 };
293         unsigned int rom_efuse[HASH_BLOCK_LEN] = { 0 };
294         unsigned int cal_efuse[HASH_BLOCK_LEN] = { 0 };
295         int i, len;
296         NBLHeader *nblheader;
297         uint8 *tmpnbl;
298
299         printf("%s, name: %s enter\r\n", __FUNCTION__, _w2c(name));
300
301         tmpnbl = malloc(sizeof(NBLHeader));
302
303         if (name && wcscmp(L"splloader0", name) != 0) {
304                 if (!secure_header_parser(header))
305                         while (1) ;
306         }
307
308         if (secureboot_enabled()) {
309                 if (name && (wcscmp(L"splloader0", name) == 0)) {
310                         /*read efuse hash values */
311                         efuse_hash_read(rom_efuse_hash, sizeof(rom_efuse_hash));
312
313                         /* memset NBLHeader & save NBLHeader */
314                         nblheader = (NBLHeader *) ((unsigned char *)header + BOOTLOADER_HEADER_OFFSET);
315                         memcpy(tmpnbl, nblheader, sizeof(NBLHeader));
316                         len = nblheader->mHashLen;
317                         /*clear header */
318                         memset(nblheader, 0, sizeof(NBLHeader));
319                         nblheader->mHashLen = len;
320                         cal_sha1(header, (nblheader->mHashLen) << 2, cal_efuse_hash);
321
322                         /*restore the NBLHeader */
323                         memcpy(nblheader, tmpnbl, sizeof(NBLHeader));
324
325                         /*convert char to int */
326                         secure_hash_str2ul(&cal_efuse[0], cal_efuse_hash, 2 * SHA1_SUM_LEN);
327                         secure_hash_str2ul(&rom_efuse[0], rom_efuse_hash, 2 * SHA1_SUM_LEN);
328
329                         for (i = 0; i < 5; i++) {
330                                 rom_efuse[i] &= (~0x80000000);  //BIT31
331                                 cal_efuse[i] &= (~0x80000000);  //BIT31
332                         }
333                         //hexdump ("setrom_efuse:", rom_efuse, sizeof (rom_efuse));
334                         //hexdump ("setpp:", cal_efuse, sizeof (cal_efuse));
335
336                         if ((rom_efuse[0] == cal_efuse[0]) && (rom_efuse[1] == cal_efuse[1]) && (rom_efuse[2] == cal_efuse[2]) && (rom_efuse[3] == cal_efuse[3])
337                             && (rom_efuse[4] == cal_efuse[4])) {
338                                 printf("efuse hash compare successful\n");
339                         } else {
340                                 printf("efuse hash compare difference\n");
341                                 while (1) ;
342                         }
343                 }
344         }
345
346         puk_addr = get_puk_addr(name, header);
347 //    hexdump("puk_addr:", puk_addr, 260);
348
349         vlr_addr = get_vlr_addr(name, header);
350
351         if (code) {
352                 code_addr = code;
353         } else {
354                 code_addr = get_code_addr(name, header);
355         }
356         printf("puk_addr=%x,vlr_addr=%x,code_addr=%x\n", puk_addr, vlr_addr, code_addr);
357
358         secure_check((uint8_t *) code_addr, ((vlr_info_t *) vlr_addr)->length, (uint8_t *) vlr_addr, (uint8_t *) puk_addr);
359 }