1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
|
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2020 Broadcom Ltd.
*/
#include <common.h>
#include <wdt.h>
#include <fdtdec.h>
#include <asm/types.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <asm/unaligned.h>
#include <malloc.h>
#include "tpl_params.h"
#include "spl_env.h"
#include "bcm_secure.h"
#include "bcm_otp.h"
#include "bcm_rng.h"
#include <asm/arch/rng.h>
#include "u-boot/rsa.h"
#include "u-boot/rsa-mod-exp.h"
#include <u-boot/sha256.h>
#include <uboot_aes.h>
#include <watchdog.h>
#include "mini-gmp/mini-gmp.h"
#include "mini-gmp/mini-mpq.h"
#define NODE_NAME_LEN 128
#define BCM_SEC_MAX_ENCODED_KEYS 10
#define BCM_SEC_MAX_EXPORTED_ITEMS 5
#define DELG_SEC_FIT_NODE_PATH "/security"
#define DELG_SEC_FIT_NODE_SIG "signature"
#define DELG_SEC_POL_PATH "/security_policy"
#define DELG_SEC_POL_DELGID "delegate_id"
#define DELG_SEC_POL_MINTPLV "min_tpl_compatibility"
#define DELG_SEC_POL_AES_KEY_PATH "/security_policy/key-aes"
#define DELG_SEC_POL_AES_KEY_ENC_ALGO "algo"
#define DELG_SEC_POL_AES_KEY_DATA "data"
#define DELG_SEC_POL_ANTI_ROLLBACK_PATH "/security_policy/anti-rollback"
#define DELG_SEC_POL_SEC_RESTRICT_PATH "/security_policy/sec_restriction"
#define DELG_SEC_POL_STATUS "status"
#define DELG_SEC_POL_STATUS_DISABLED "disabled"
#define DELG_SEC_POL_NEW_ANTIROLLBCK "new_antirollback"
#define DELG_SEC_POL_ANTIROLLBCK_LIM "antirollback_limit"
#define DELG_SEC_POL_HW_STATE_PATH "/security_policy/sec_restriction/hw_state"
#define DELG_HW_STATE_PATH "/trust/hw_state"
#define DELG_ANTI_ROLLBACK_PATH "/trust/anti-rollback"
#define DELG_ENC_KEYS_PATH "/trust/encoded_keys"
#define DELG_ENC_KEYS_NAME "key_name"
#define DELG_ENC_KEYS_PERM "permission"
#define DELG_ENC_KEYS_SIZE "size"
#define DELG_ENC_KEYS_DATA DELG_SEC_POL_AES_KEY_DATA
#define DELG_ENC_KEYS_LDADDR "load_addr"
#define DELG_ENC_KEYS_ALGO DELG_SEC_POL_AES_KEY_ENC_ALGO
#define DELG_ENC_KEYS_PERMSEC "secure"
#define DELG_ENC_KEYS_PERMNONSEC "nonsecure"
#define DELG_TRUST_NODE_PATH "/trust"
#define DELG_TRUST_NODE "trust"
#define DELG_SEC_POL_SEC_EXPORT_PATH "/security_policy/sec_restriction/sec_exports"
#define DELG_SEC_ALLOWED_EXPORTS "allowed_exports"
#define DELG_SEC_EXPORT_PATH "/trust/sec_exports"
#define DELG_EXP_ITEM_NAME "item_name"
#define DELG_EXP_ITEM_ID "item_sec_id"
#define DELG_EXP_ITEM_LENGTH "length"
#define DELG_EXP_ITEM_SALT "salt"
#define DELG_EXP_ITEM_ALGO DELG_SEC_POL_AES_KEY_ENC_ALGO
static int sec_add_export_item_fdt( u8 * fdt, bcm_sec_export_item_t* item );
static int bcm_sec_set_sotp_hw_state(u8* fit, int node, bcm_sec_cb_arg_t* sotp_st_arg);
static int bcm_sec_set_rng_hw_state(u8* fit, int node, bcm_sec_cb_arg_t* rng_st_arg);
typedef struct sec_exp_item_otp_map {
char item_id[NODE_NAME_LEN];
otp_map_feat_t otp_feat;
} sec_exp_item_otp_map_t;
sec_exp_item_otp_map_t exp_item_otp_map[] = {
{ "SEC_ITEM_KEY_DEV_SPECIFIC" , SOTP_MAP_KEY_DEV_SPECIFIC},
{ "SEC_ITEM_SER_NUM" , SOTP_MAP_SER_NUM},
{ "" , OTP_MAP_MAX}
};
void bcm_sec_clean_secmem(bcm_sec_t* sec)
{
if ( sec->state & SEC_STATE_SECURE) {
memset((void*)bcm_secbt_args(), 0, sizeof(bcm_secbt_args_t));
}
}
static int sec_otp_ctrl(bcm_sec_t* sec, bcm_sec_ctrl_t ctrl, void* arg)
{
switch(ctrl) {
case SEC_CTRL_SOTP_LOCK_ALL:
/* Lock access to all otp keycontent including register access to the controller for both secure/non-secure masters*/
{
if (bcm_sotp_ctl_perm(OTP_HW_CMN_CTL_LOCK,
OTP_HW_CMN_CTL_LOCK_ALL, NULL) == OTP_MAP_CMN_ERR_UNSP) {
printf("WARNING: lock is not supported\n");
}
}
break;
case SEC_CTRL_SOTP_UNLOCK_SOTP_UNSEC_PROV: {
/*
* unlock non secure masters in provisioning mode --> readlock all nonzero rows
*/
if (bcm_sotp_ctl_perm(OTP_HW_CMN_CTL_UNLOCK,
OTP_HW_CMN_CTL_LOCK_NS_PROV, NULL) == OTP_MAP_CMN_ERR_UNSP) {
printf("WARNING: unlock is not supported\n");
}
break;
}
break;
case SEC_CTRL_SOTP_UNLOCK_SOTP_UNSEC: {
/*
* unlock non secure masters
*/
if (bcm_sotp_ctl_perm(OTP_HW_CMN_CTL_UNLOCK,
OTP_HW_CMN_CTL_LOCK_NS, NULL) == OTP_MAP_CMN_ERR_UNSP) {
printf("WARNING: unlock is not supported\n");
}
break;
}
break;
case SEC_CTRL_SOTP_UNLOCK_SOTP_SEC: {
/* unlock secure masters*/
if (bcm_sotp_ctl_perm(OTP_HW_CMN_CTL_UNLOCK,
OTP_HW_CMN_CTL_LOCK_S, NULL) == OTP_MAP_CMN_ERR_UNSP) {
printf("WARNING: unlock is not supported\n");
}
}
break;
default:
break;
}
return 0;
}
static int sec_rng_ctrl(bcm_sec_t* sec, bcm_sec_ctrl_t ctrl, void* arg)
{
switch(ctrl) {
case SEC_CTRL_RNG_LOCK_ALL:
rng_pac_lock(RNG_PERM_DISABLE_ALL);
break;
case SEC_CTRL_RNG_UNLOCK_RNG_UNSEC:
rng_pac_lock(RNG_PERM_NSEC_ENABLE);
break;
case SEC_CTRL_RNG_UNLOCK_RNG_SEC:
rng_pac_lock(RNG_PERM_SEC_ENABLE);
break;
default:
break;
}
return 0;
}
static int sec_add_fdt_node( u8 * fdt, char * path, char * nodename)
{
int node = -1;
printf("INFO: Creating %s/%s\n", path, nodename);
/*
* Parameters: Node path, new node to be appended to the path.
*/
node = fdt_path_offset (fdt, path);
if (node < 0) {
/*
* Not found or something else bad happened.
*/
printf ("libfdt fdt_path_offset() returned %s\n",
fdt_strerror(node));
return -1;
}
node = fdt_add_subnode(fdt, node, nodename);
if (node < 0) {
printf ("libfdt fdt_add_subnode(): %s\n",
fdt_strerror(node));
return -1;
}
return node;
}
static int sec_get_export_item( char * item_id, u8 ** data, u32 * size )
{
int i = 0;
int rc = -1;
while( exp_item_otp_map[i].item_id ) {
if( (strncasecmp(exp_item_otp_map[i].item_id, item_id, NODE_NAME_LEN) == 0))
{
printf("INFO: Found matching item for %s = %d\n", item_id,
exp_item_otp_map[i].otp_feat);
break;
}
i++;
}
if( exp_item_otp_map[i].otp_feat != OTP_MAP_MAX )
rc = bcm_otp_read(exp_item_otp_map[i].otp_feat, (u32**)data, size);
return rc;
}
static int sec_salt_hash_item( u8 * item_src, int size_src,
u8* item_dest, int size_dst,
char * algo, int salt)
{
char * temp_buff;
char * buf_ptr;
char * dst_ptr;
/* Allocate temp mem of src size + size of 32-bit salt */
temp_buff = malloc(size_src + sizeof(int));
if (!temp_buff) {
printf("ERROR: Cannot allocate memory tempbuff\n");
return -1;
}
/* Init buffer pointers */
buf_ptr = (char*)temp_buff;
dst_ptr = (char*)item_dest;
//TODO: Support other algorithms rather than just sha256
if( (size_dst % SHA256_SUM_LEN) || size_dst > 2*SHA256_SUM_LEN ) {
printf("ERROR: Unsupported final item size %d for hashing!\n", size_dst);
return -1;
}
/* First pass, get first 256bits of obfuscated item data */
if( salt ) {
memcpy(buf_ptr, &salt, sizeof(int));
buf_ptr += sizeof(int);
}
memcpy(buf_ptr, item_src, size_src);
//TODO: Handle other algorigthms, hardcoding to sha256
bcm_sec_digest( temp_buff, size_src + sizeof(int), dst_ptr, "sha256");
dst_ptr += SHA256_SUM_LEN;
/* 2nd pass, get 2nd 256bits of obfuscated item data, reverse order of salting */
if( size_dst > SHA256_SUM_LEN ) {
buf_ptr = temp_buff;
memcpy(buf_ptr, item_src, size_src);
buf_ptr += size_src;
if( salt ) {
memcpy(buf_ptr, &salt, sizeof(int));
buf_ptr += sizeof(u32);
}
//TODO: Handle other algorigthms, hardcoding to sha256
bcm_sec_digest(temp_buff, size_src + sizeof(int), dst_ptr, "sha256");
}
free(temp_buff);
return 0;
}
static int sec_add_export_item_fdt( u8 * fdt, bcm_sec_export_item_t* item )
{
int node = -1;
char node_name[NODE_NAME_LEN];
int ret = -1;
u8 * temp_buff = NULL;
u8 * pdata = NULL;
u32 data_size = 0;
/* Get the exported item */
if( !item->value ) {
/* Get items */
if( !item->id || !item->len ) {
printf("INFO: Skipping exported item %s %s %d\n", item->name, item->id, item->len);
ret = 0;
goto err;
}
/* Get the item */
ret = sec_get_export_item( item->id, &pdata, &data_size );
if( ret ) {
printf("INFO: Cannot retrieve export item %s! Skipping!\n", item->name);
ret = 0;
goto err;
}
/* Allocate memory for value */
temp_buff = malloc(item->len);
if (!temp_buff) {
printf("ERROR: Cannot allocate memory for export item\n");
ret = -1;
goto err;
}
memset(temp_buff,0,item->len);
/* Salt and/or hash the item */
if( item->algo ) {
ret = sec_salt_hash_item( (u8*) pdata, data_size, temp_buff, item->len, item->algo, item->salt );
if( ret ) {
printf("INFO: Cannot salt/hash item %s! Skipping!\n", item->name);
ret = 0;
goto err;
}
} else {
memcpy(temp_buff, pdata, (data_size>item->len?item->len:data_size));
}
/* Set value */
item->value = temp_buff;
}
/* Create /trust node if it doesnt exits */
node = fdt_path_offset (fdt, DELG_TRUST_NODE_PATH);
if(node < 0) {
node = sec_add_fdt_node( fdt, "/", DELG_TRUST_NODE);
if( node < 0) {
printf("ERROR: Could not create %s node!\n", DELG_TRUST_NODE_PATH);
ret = -1;
goto err;
}
}
/* Add item node */
snprintf(node_name,NODE_NAME_LEN,item->name);
node = sec_add_fdt_node( fdt, DELG_TRUST_NODE_PATH, node_name);
if( node < 0 ) {
printf("ERROR: Could not add %s node to %s!\n",
node_name, DELG_TRUST_NODE_PATH);
ret = -1;
goto err;
}
printf("INFO: Adding exported item node %s to dtb, size:%d\n", node_name, item->len);
/* Add the item value */
ret = fdt_setprop(fdt, node, "value", item->value, item->len);
if( ret ) {
printf("ERROR: Could net set value for %s/%s\n",DELG_TRUST_NODE_PATH,node_name);
goto err;
}
/* Set the export flag */
if( !ret && item->exp_flag ) {
ret = fdt_setprop(fdt, node, "export", "yes", strlen("yes")+1);
if( ret ) {
printf("ERROR: Could not set %s/%s/export\n",DELG_TRUST_NODE_PATH,node_name);
goto err;
}
}
err:
if( temp_buff )
free(temp_buff);
return ret;
}
static int sec_add_decoded_key_fdt( u8 * fdt, char* key_name, u8 * key_val, int key_len)
{
int node = -1;
char key_node_name[NODE_NAME_LEN];
int ret = -1;
node = fdt_path_offset (fdt, DELG_TRUST_NODE_PATH);
/* Create /trust node if it doesnt exits */
if(node < 0) {
node = sec_add_fdt_node( fdt, "/", DELG_TRUST_NODE);
if( node < 0) {
printf("ERROR: Could not create %s node!\n", DELG_TRUST_NODE_PATH);
return -1;
}
}
/* Add key node */
snprintf(key_node_name,NODE_NAME_LEN,"key_%s", key_name);
node = sec_add_fdt_node( fdt, DELG_TRUST_NODE_PATH, key_node_name);
if( node < 0 ) {
printf("ERROR: Could not add %s node to %s!\n",
key_node_name, DELG_TRUST_NODE_PATH);
return -1;
}
ret = fdt_setprop(fdt, node, "value", key_val, key_len);
if( ret )
printf("ERROR: Could net set value for %s/%s\n",DELG_TRUST_NODE_PATH,key_node_name);
return ret;
}
static int sec_key_ctrl(bcm_sec_t *sec, bcm_sec_ctrl_t ctrl, void * arg)
{
int rc = 0;
u8* ek_iv = NULL;
u8* key_data = NULL;
switch(ctrl) {
case SEC_CTRL_KEY_GET:
{
if ( sec->state & SEC_STATE_SECURE) {
bcm_sec_btrm_key_info(sec);
} else {
u8* env_key = bcm_util_env_var2bin("brcm_pub_testkey", RSA2048_BYTES);
/* We've got test key; try to authenticate with it
* Only works in non-secure mode
* */
if (!env_key) {
debug("No Key in environment \n");
} else {
memcpy(sec->key.rsa_pub, env_key, RSA2048_BYTES);
sec->key.pub = sec->key.rsa_pub;
}
}
}
break;
case SEC_CTRL_KEY_CHAIN_RSA:
if (sec->state&SEC_STATE_SECURE) {
bcm_sec_export_item_t item;
u32 lvl = 0;
item.salt = 0;
item.algo = NULL;
item.exp_flag = 1;
bcm_sec_get_antirollback_lvl(&lvl);
lvl = cpu_to_be32(lvl);
item.name = "antirollback_lvl";
item.len = sizeof(u32);
item.value = (u8*)&lvl;
rc = sec_add_export_item_fdt(arg, &item);
if( rc == 0 ) {
item.name = "brcm_pub_key";
item.len = RSA2048_BYTES;
item.value = sec->key.pub;
rc = sec_add_export_item_fdt(arg, &item);
if (!sec->key.pub || rc ) {
rc = -1;
printf("ERROR: unable to chain pub_key\n");
}
}
}
break;
case SEC_CTRL_KEY_EXPORT_ITEM:
if (sec->state&SEC_STATE_SECURE) {
int i;
bcm_sec_key_arg_t* sec_arg = arg;
for (i = 0; i<sec_arg->len; i++) {
sec_add_export_item_fdt(sec_arg->arg,
&sec_arg->item[i]);
}
}
break;
case SEC_CTRL_KEY_CHAIN_ENCKEY:
if (sec->state&SEC_STATE_SECURE) {
int i;
bcm_sec_key_arg_t* sec_arg = arg;
for (i = 0; i<sec_arg->len; i++) {
/* Decrypt encoded key */
bcm_sec_get_active_aes_key(&ek_iv);
/* FIXME: Compare un-enc and enc sizes to figure out malloc length ( we are assuming enc > un-enc ) */
key_data = malloc(sec_arg->enc_key[i].size_enc);
if (!key_data) {
printf("ERROR: Cannot allocate memory for decoded key size %d!\n", sec_arg->enc_key[i].size_enc);
return -1;
}
memcpy(key_data, sec_arg->enc_key[i].data, sec_arg->enc_key[i].size_enc);
bcm_sec_aes_cbc128((u8*)ek_iv, (u8*)ek_iv + AES128_KEY_LENGTH, key_data, sec_arg->enc_key[i].size_enc,0);
debug("KEYDECRYPT: encr:0x%08x key:0x%08x decr:0x%08x\n", *(u32*)sec_arg->enc_key[i].data, *(u32*)ek_iv, *(u32*)key_data);
/* If no permissions are set, assume secure key */
if( !sec_arg->enc_key[i].perm ||
(strcasecmp(sec_arg->enc_key[i].perm, DELG_ENC_KEYS_PERMSEC) == 0) ) {
/* For secure keys see if there is a load address */
if( sec_arg->enc_key[i].load_addr ) {
printf("INFO: copying key %s to %p\n",
sec_arg->enc_key[i].name,(void*)sec_arg->enc_key[i].load_addr);
printf("INFO: copying to load addr disabled for now!\n");
//memcpy((void*)sec_arg->enc_key[i].load_addr, key_data, sec_arg->enc_key[i].size);
} else {
printf("INFO: No load address specified for secure key %s! Ignoring\n", sec_arg->enc_key[i].name);
}
} else {
/* For non-secure keys add them to dtb */
sec_add_decoded_key_fdt(sec_arg->arg,
sec_arg->enc_key[i].name,
key_data,
sec_arg->enc_key[i].size);
}
free(key_data);
key_data = NULL;
}
}
break;
case SEC_CTRL_KEY_CHAIN_AES:
if (sec->state&SEC_STATE_SECURE) {
int i;
bcm_sec_export_item_t item;
bcm_sec_key_arg_t* sec_arg = arg;
item.salt = 0;
item.algo = NULL;
item.exp_flag = 0;
for (i = 0; i< sec_arg->len; i++) {
item.name = sec_arg->aes[i].id;
item.len = BCM_SECBT_AES_CBC128_EK_LEN*2;
item.value = sec_arg->aes[i].key;
if (sec_add_export_item_fdt(sec_arg->arg, &item)) {
rc = -1;
printf("ERROR: unable to chain aes_key\n");
}
}
}
break;
case SEC_CTRL_KEY_CLEAN_SEC_MEM:
memset((void*)bcm_secbt_args(),0, sizeof(bcm_secbt_args_t));
break;
case SEC_CTRL_KEY_CLEAN_ALL:
bcm_sec_clean_secmem(sec);
bcm_sec_clean_keys(sec);
break;
default:
break;
}
return rc;
}
void bcm_sec_cb_init(bcm_sec_t* sec)
{
sec->cb[SEC_CTRL_ARG_KEY].cb = sec_key_ctrl;
sec->cb[SEC_CTRL_ARG_SOTP].cb = sec_otp_ctrl;
sec->cb[SEC_CTRL_ARG_RNG].cb = sec_rng_ctrl;
}
void bcm_sec_get_root_aes_key(u8** key)
{
*key = bcm_sec()->key.aes_ek;
}
u8* bcm_sec_get_root_pub_key(void)
{
return bcm_sec()->key.rsa_pub;
}
static void bcm_sec_set_delg_cfg( bcm_sec_delg_cfg * cfg )
{
bcm_sec()->delg_cfg_obj = cfg;
}
bcm_sec_delg_cfg * bcm_sec_get_delg_cfg(void)
{
return bcm_sec()->delg_cfg_obj;
}
bcm_sec_export_item_t bcm_sec_exported_items[BCM_SEC_MAX_EXPORTED_ITEMS];
static int bcm_sec_process_exports(u8 * fit_hdr, bcm_sec_cb_arg_t* key_args)
{
u8 * fit_ptr = NULL;
bcm_sec_delg_cfg* delg_cfg = bcm_sec_get_delg_cfg();
char * allowed_exports = NULL;
bcm_sec_key_arg_t * item_list;
int sec_export_offset = -1;
int exp_item_offset = -1;
int count = 0;
int ndepth = 0;
int * value = NULL;
/* IF delegations are active then sec_exports in security
* policy control delegate requested exports */
if( delg_cfg && delg_cfg->delg_id )
{
fit_ptr = delg_cfg->sec_policy_fit;
sec_export_offset = fdt_path_offset (fit_ptr, DELG_SEC_POL_SEC_EXPORT_PATH);
if (sec_export_offset < 0) {
debug("INFO: Could not find %s in security policy\n", DELG_SEC_POL_SEC_EXPORT_PATH);
} else {
/* Check if sec_export_offset is disabled */
value = (int*)fdt_getprop((void *)fit_ptr, sec_export_offset, DELG_SEC_POL_STATUS, NULL);
if (value && (strcasecmp((const char*)value, DELG_SEC_POL_STATUS_DISABLED) == 0)){
printf("INFO: Found DISABLED %s in security policy\n", DELG_SEC_POL_SEC_EXPORT_PATH);
sec_export_offset = -1;
} else {
printf("INFO: Found %s in security policy\n", DELG_SEC_POL_SEC_EXPORT_PATH);
}
allowed_exports = (char*)fdt_getprop((void *)fit_ptr, sec_export_offset, DELG_SEC_ALLOWED_EXPORTS, NULL);
if( !allowed_exports || strlen((const char*)allowed_exports) == 0 ) {
/* No exports allowed */
sec_export_offset = -1;
}
}
}
/* If no policy export node or if policy export is disabled, simply return */
if( sec_export_offset < 0 ) {
return 0;
}
/* Check delegate's requested exports */
if( fit_hdr ) {
delg_cfg = NULL;
fit_ptr = fit_hdr;
sec_export_offset = fdt_path_offset (fit_ptr, DELG_SEC_EXPORT_PATH);
if (sec_export_offset < 0) {
debug("INFO: Could not find %s in fit\n", DELG_SEC_EXPORT_PATH);
return 0;
} else {
/* Check if sec_export_offset is disabled */
value = (int*)fdt_getprop((void *)fit_ptr, sec_export_offset, DELG_SEC_POL_STATUS, NULL);
if (value && (strcasecmp((const char*)value, DELG_SEC_POL_STATUS_DISABLED) == 0)){
printf("INFO: Found DISABLED %s in fit\n", DELG_SEC_EXPORT_PATH);
sec_export_offset = -1;
} else {
printf("INFO: Found %s in fit\n", DELG_SEC_EXPORT_PATH);
}
}
}
if (sec_export_offset) {
/* Process all image subnodes */
for (ndepth = 0, count = 0,
exp_item_offset = fdt_next_node(fit_hdr, sec_export_offset, &ndepth);
(exp_item_offset >= 0) && (ndepth > 0);
exp_item_offset = fdt_next_node(fit_hdr, exp_item_offset, &ndepth)) {
if (ndepth == 1) {
/*
* Direct child node of the sec_export parent node,
* i.e. item node.
*/
/* Get key name */
bcm_sec_exported_items[count].value = NULL;
bcm_sec_exported_items[count].name = (char*)fdt_getprop((void *)fit_hdr, exp_item_offset, DELG_EXP_ITEM_NAME, NULL);
bcm_sec_exported_items[count].id = (char*)fdt_getprop((void *)fit_hdr, exp_item_offset, DELG_EXP_ITEM_ID, NULL);
value = (int*)fdt_getprop((void *)fit_hdr, exp_item_offset, DELG_EXP_ITEM_LENGTH, NULL);
if( !bcm_sec_exported_items[count].name || !bcm_sec_exported_items[count].id || !value )
continue;
printf("INFO: Found item:%s id:%s in fit\n", bcm_sec_exported_items[count].name, bcm_sec_exported_items[count].id);
/* Check if requested item is allowed to be exported */
if( !strstr(allowed_exports, bcm_sec_exported_items[count].id))
continue;
bcm_sec_exported_items[count].len = be32_to_cpu(*value);
if( !bcm_sec_exported_items[count].len)
continue;
/* Get optional 32-bit salt */
value = (int*)fdt_getprop((void *)fit_hdr, exp_item_offset, DELG_EXP_ITEM_SALT, NULL);
if( value )
bcm_sec_exported_items[count].salt = be32_to_cpu(*value);
/* Get optional hashing algorithm */
bcm_sec_exported_items[count].algo = (char*)fdt_getprop((void *)fit_hdr, exp_item_offset, DELG_EXP_ITEM_ALGO, NULL);
bcm_sec_exported_items[count].exp_flag = 1;
count++;
if( count >= BCM_SEC_MAX_EXPORTED_ITEMS ) {
printf("INFO: Max secure export item limit of %d items reached! Ignoring other items!\n", BCM_SEC_MAX_EXPORTED_ITEMS);
break;
}
}
}
}
if( count ) {
item_list = malloc(sizeof(bcm_sec_key_arg_t));
if (!item_list) {
printf("ERROR: Cannot allocate memory for exported item list!\n");
return -1;
}
item_list->len = count;
item_list->item = &bcm_sec_exported_items[0];
key_args->arg[2].ctrl = SEC_CTRL_KEY_EXPORT_ITEM;
key_args->arg[2].ctrl_arg = item_list;
}
return 0;
}
static int bcm_sec_get_antirollback_node( u8 * fit, char * path, int * req_antirollback, int * antirollback_limit)
{
/* Get key-owners antirollback update node from policy */
int * value = NULL;
int nodeoffset = fdt_path_offset((void *)fit, path);
if( nodeoffset < 0 ) {
printf("INFO: %s node NOT found!\n", path);
} else {
/* Check if node is disabled */
value = (int*)fdt_getprop((void *)fit, nodeoffset, DELG_SEC_POL_STATUS, NULL);
if (value && (strcasecmp((const char*)value, DELG_SEC_POL_STATUS_DISABLED) == 0)) {
nodeoffset = -1;
printf("INFO: Disabled %s node found!\n", path);
} else {
printf("INFO: %s node found !\n", path);
/* retrieve anti=rollback settings */
value = (int*)fdt_getprop((void *)fit, nodeoffset, DELG_SEC_POL_NEW_ANTIROLLBCK, NULL);
if (value && req_antirollback )
*req_antirollback = be32_to_cpu(*value);
value = (int*)fdt_getprop((void *)fit, nodeoffset, DELG_SEC_POL_ANTIROLLBCK_LIM, NULL);
if (value && antirollback_limit )
*antirollback_limit = be32_to_cpu(*value);
}
}
return nodeoffset;
}
static int bcm_sec_process_antirollback( u8 * fit_hdr)
{
/* Process rollback update node for both key-owner and delegate.
* key-owner's rollback update node can limit the rollback levels that
* can be updated by delegate */
u32 pol_req_antirollback = 0;
u32 pol_antirollback_limit = 0;
u32 delg_req_antirollback = 0;
u32 commit_antirollback = 0;
u32 current_antirollback = 0;
u32 delg_maximum_antirollback = 0;
int nodeoffset_pol = -1;
int nodeoffset_fit = -1;
bcm_sec_delg_cfg * delg_cfg = NULL;
int ret = -1;
/* Get current anti-rollback level */
bcm_sec_get_antirollback_lvl(¤t_antirollback);
/* Check if delegations are active, get key-owners antirollback settings */
delg_cfg = bcm_sec_get_delg_cfg();
if( delg_cfg && delg_cfg->delg_id ) {
/* Get maximum rollback valid for this delegation */
delg_maximum_antirollback = delg_cfg->max_antirollback;
/* Get key-owners antirollback update node from policy */
nodeoffset_pol = bcm_sec_get_antirollback_node((void *)delg_cfg->sec_policy_fit, DELG_SEC_POL_ANTI_ROLLBACK_PATH,
(int*)&pol_req_antirollback, (int*)&pol_antirollback_limit);
}
/* Get delegates antirollback update node from main FIT hdr */
if( fit_hdr ) {
nodeoffset_pol = bcm_sec_get_antirollback_node((void *)fit_hdr, DELG_ANTI_ROLLBACK_PATH,
(int*)&delg_req_antirollback, NULL);
}
/* Early return if no node found */
if ((nodeoffset_pol < 0) && (nodeoffset_fit < 0)) {
return 0;
}
printf("INFO: ko_rb:%d kp_lim:%d delg_rb:%d max:%d curr:%d\n",
pol_req_antirollback, pol_antirollback_limit, delg_req_antirollback,
delg_maximum_antirollback, current_antirollback);
/* Verify key-owners requested antirollback */
if( pol_req_antirollback ) {
if( pol_req_antirollback > delg_maximum_antirollback ) {
printf("ERROR: Invalid security policy requested antirollback:%d, Max:%d\n",
pol_req_antirollback, delg_maximum_antirollback);
return ret;
}
}
/* Ensure that key-owner's anti-rollback limit for delegate's falls within the max allowable */
if( !pol_antirollback_limit || (pol_antirollback_limit > delg_maximum_antirollback) )
pol_antirollback_limit = delg_maximum_antirollback;
/* Verify delegates requested antirollback */
if( delg_req_antirollback && pol_antirollback_limit ) {
if( delg_req_antirollback > pol_antirollback_limit) {
printf("INFO: Invalid FIT requested antirollback:%d, Max:%d\n",
delg_req_antirollback, pol_antirollback_limit);
delg_req_antirollback = 0;
}
}
/* Figure out the antirollback level to commit */
if (delg_req_antirollback > pol_req_antirollback)
commit_antirollback = delg_req_antirollback;
else
commit_antirollback = pol_req_antirollback;
/* Do boundary checks */
if( !commit_antirollback || (commit_antirollback <= current_antirollback) ) {
printf("INFO: Not committing requested anti_rollback level %d! Min:%d\n",
commit_antirollback,current_antirollback);
ret = 0;
} else {
/* commit the antirollback */
printf("INFO: Committing antirollback level:%d\n", commit_antirollback);
ret = bcm_sec_set_antirollback_lvl(commit_antirollback);
}
return ret;
}
static int bcm_sec_process_hw_state(u8 * fit_hdr, bcm_sec_cb_arg_t* sotp_st_arg, bcm_sec_cb_arg_t* rng_st_arg)
{
int * value = 0;
u8 * fit_ptr = NULL;
bcm_sec_state_t st = bcm_sec_state();
bcm_sec_delg_cfg* delg_cfg = bcm_sec_get_delg_cfg();
int node = -1;
/* IF delegations are active then hw_state in security
* policy overrides delegate specified state */
if( delg_cfg && delg_cfg->delg_id )
{
fit_ptr = delg_cfg->sec_policy_fit;
node = fdt_path_offset (fit_ptr, DELG_SEC_POL_HW_STATE_PATH);
if (node < 0) {
debug("INFO: Could not find %s node in security policy\n", DELG_SEC_POL_HW_STATE_PATH);
} else {
/* Check if node is disabled */
value = (int*)fdt_getprop((void *)fit_ptr, node, DELG_SEC_POL_STATUS, NULL);
if (value && (strcasecmp((const char*)value, DELG_SEC_POL_STATUS_DISABLED) == 0)){
printf("INFO: Found DISABLED %s node in security policy\n", DELG_SEC_POL_HW_STATE_PATH);
node = -1;
} else {
printf("INFO: Found %s node in security policy\n", DELG_SEC_POL_HW_STATE_PATH);
}
}
}
/* Check delegate's specified hw_state */
if( (node < 0) && fit_hdr ) {
delg_cfg = NULL;
fit_ptr = fit_hdr;
node = fdt_path_offset (fit_ptr, DELG_HW_STATE_PATH);
if (node < 0) {
debug("INFO: Could not find %s node in fit\n", DELG_HW_STATE_PATH);
node = -1;
} else {
/* Check if node is disabled */
value = (int*)fdt_getprop((void *)fit_ptr, node, DELG_SEC_POL_STATUS, NULL);
if (value && (strcasecmp((const char*)value, DELG_SEC_POL_STATUS_DISABLED) == 0)){
printf("INFO: Found DISABLED %s node in fit\n", DELG_HW_STATE_PATH);
node = -1;
} else {
printf("INFO: Found %s node in fit\n", DELG_HW_STATE_PATH);
}
}
}
/* Set the default hw state */
/* If in secure mode and sotp-lock not specified --> LOCK by default
* If in NON-secure mode and sotp-lock not specified --> UNLOCK by default */
/* If in secure mode and rng-lock not specified --> LOCK by default
* If in NON-secure mode and rng-lock not specified --> UNLOCK by default */
if(st == SEC_STATE_SECURE) {
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_LOCK_ALL;
rng_st_arg->arg[0].ctrl = SEC_CTRL_RNG_LOCK_ALL;
} else {
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_UNLOCK_SOTP_UNSEC;
rng_st_arg->arg[0].ctrl = SEC_CTRL_RNG_UNLOCK_RNG_UNSEC;
}
if( node >= 0 ) {
/* set hw state from node */
bcm_sec_set_sotp_hw_state(fit_ptr, node, sotp_st_arg);
bcm_sec_set_rng_hw_state(fit_ptr, node, rng_st_arg);
}
return 0;
}
static int bcm_sec_delg_pre_process_restrictions(u8 * policy_fdt, u8 * fit_hdr)
{
/* TODO: Pre Process s/w restrictions here */
return 0;
}
bcm_sec_enc_key_arg_t bcm_sec_encoded_keys[BCM_SEC_MAX_ENCODED_KEYS];
static int bcm_sec_process_encoded_keys(u8 * fit_hdr, bcm_sec_cb_arg_t* key_args)
{
/* TODO: Encoded keys could be present in security node or outside security node.
* Keys inside security node will be encrypted via the root aes key. Keys outside
* the security node will be encrypted via the active (delegated) aes key.
* These keys will have security permissions. These keys need to be added to the
* key_chain so that they can be exported to the next level of software in
* spl_perform_fixups */
int enc_keys_offset = -1;
int key_offset = -1;
int count = 0;
int ndepth = 0;
int * value = NULL;
bcm_sec_key_arg_t *enc_keys;
bcm_sec_delg_cfg* delg_cfg = bcm_sec_get_delg_cfg();
/* Process key-owners encoded keys in security node if present
* These keys are encrypted using ROE */
if( delg_cfg && delg_cfg->delg_id )
{
/* TODO: Handle key-owners encoded keys */
}
/* Process delegates encoded keys in FIT header
* These keys are encrypted using the active AES key */
enc_keys_offset = fdt_path_offset (fit_hdr, DELG_ENC_KEYS_PATH);
if (enc_keys_offset < 0) {
debug("INFO: Could not find %s node in fit\n", DELG_ENC_KEYS_PATH);
return 0;
} else {
/* Process all image subnodes */
for (ndepth = 0, count = 0,
key_offset = fdt_next_node(fit_hdr, enc_keys_offset, &ndepth);
(key_offset >= 0) && (ndepth > 0);
key_offset = fdt_next_node(fit_hdr, key_offset, &ndepth)) {
if (ndepth == 1) {
/*
* Direct child node of the encoded_keys parent node,
* i.e. key node.
*/
/* Get key name */
bcm_sec_encoded_keys[count].name = (char*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_NAME, NULL);
if (bcm_sec_encoded_keys[count].name == NULL)
{
printf("INFO: Can't find %s parameter in key node under %s \n", DELG_ENC_KEYS_NAME,
DELG_ENC_KEYS_PATH);
continue;
}
printf("INFO: Found key %s in under %s\n", bcm_sec_encoded_keys[count].name, DELG_ENC_KEYS_PATH);
/* Get unencrypted size */
value = (int*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_SIZE, NULL);
if( value ) {
bcm_sec_encoded_keys[count].size = be32_to_cpu(*value);
} else {
printf("INFO: Unencrypted size for key %s is not specified! Skipping Key!\n",
bcm_sec_encoded_keys[count].name);
continue;
}
/* Get keydata */
value = (int*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_DATA, (int*)&bcm_sec_encoded_keys[count].size_enc);
if( value && bcm_sec_encoded_keys[count].size_enc ) {
bcm_sec_encoded_keys[count].data = (u8*)value;
} else {
printf("INFO: Key data for key %s not found! Skipping Key!\n",
bcm_sec_encoded_keys[count].name);
continue;
}
/* Get load address (optional) */
value = (int*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_LDADDR, NULL);
if( value )
bcm_sec_encoded_keys[count].load_addr = be64_to_cpu(*value);
/* Get load permissions and enc algorithm (optional) */
bcm_sec_encoded_keys[count].perm = (char*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_PERM, NULL);
bcm_sec_encoded_keys[count].algo = (char*)fdt_getprop((void *)fit_hdr, key_offset, DELG_ENC_KEYS_ALGO, NULL);
count++;
if( count >= BCM_SEC_MAX_ENCODED_KEYS ) {
printf("INFO: Max encoded key limit of %d keys reached! Ignoring other keys!\n", BCM_SEC_MAX_ENCODED_KEYS);
break;
}
}
}
}
/* Add detected keys */
if( count ) {
enc_keys = malloc(sizeof(bcm_sec_key_arg_t));
if (!enc_keys) {
printf("ERROR: Cannot allocate memory for encoded key ring!\n");
return -1;
}
enc_keys->len = count;
enc_keys->enc_key = &bcm_sec_encoded_keys[0];
key_args->arg[1].ctrl = SEC_CTRL_KEY_CHAIN_ENCKEY;
key_args->arg[1].ctrl_arg = enc_keys;
}
return 0;
}
static int bcm_sec_delg_process_policy(u8 * policy_fdt, u8 * fit_hdr )
{
u32 * value;
u32 pol_delg_id;
u32 min_tpl_version;
char * key_enc_alg;
u8 * key_data;
int key_len;
int nodeoffset = 0;
bcm_sec_delg_cfg * delg_cfg = NULL;
int ret = -1;
/* Get delegation config */
delg_cfg = bcm_sec_get_delg_cfg();
if( !delg_cfg ) {
printf("ERROR: Delegation configuration not found!\n");
return ret;
}
/* Get security policy node */
nodeoffset = fdt_path_offset((void *)policy_fdt, DELG_SEC_POL_PATH);
if( nodeoffset < 0 ) {
printf("ERROR: %s node not found in security policy!\n", DELG_SEC_POL_PATH);
return ret;
}
/* Get delegate id */
value = (u32*)fdt_getprop((void *)policy_fdt, nodeoffset, DELG_SEC_POL_DELGID, NULL);
if (value == NULL)
{
printf("Can't find %s parameter in %s\n", DELG_SEC_POL_DELGID,
DELG_SEC_POL_PATH);
return ret;
}
pol_delg_id = be32_to_cpu(*value);
if( pol_delg_id != delg_cfg->delg_id ) {
printf("ERROR: delegate ID mismatch! %d != %d !\n", delg_cfg->delg_id, pol_delg_id);
return ret;
}
/* get min tpl version */
value = (u32*)fdt_getprop((void *)policy_fdt, nodeoffset, DELG_SEC_POL_MINTPLV, NULL);
if (value == NULL)
{
printf("Can't find %s parameter in %s\n", DELG_SEC_POL_MINTPLV,
DELG_SEC_POL_PATH);
return 0;
}
//TODO: Compare TPL version to something
min_tpl_version = be32_to_cpu(*value);
/* 1 - Get delegated AES key (MANDATORY) */
nodeoffset = fdt_path_offset((void *)policy_fdt, DELG_SEC_POL_AES_KEY_PATH);
if( nodeoffset < 0 ) {
printf("ERROR: %s node not found in bundle!\n", DELG_SEC_POL_AES_KEY_PATH);
return ret;
}
/* Get encryption algorithm */
value = (u32*)fdt_getprop((void *)policy_fdt, nodeoffset, DELG_SEC_POL_AES_KEY_ENC_ALGO, NULL);
if (value == NULL)
{
printf("Can't find %s parameter in %s\n", DELG_SEC_POL_AES_KEY_ENC_ALGO,
DELG_SEC_POL_AES_KEY_PATH);
return ret;
}
// TODO: Support other encryption algorithms
key_enc_alg = (char*)value;
/* Get key data */
value = (u32*)fdt_getprop((void *)policy_fdt, nodeoffset, DELG_SEC_POL_AES_KEY_DATA, &key_len);
if (value == NULL)
{
printf("Can't find %s parameter in %s\n", DELG_SEC_POL_AES_KEY_DATA,
DELG_SEC_POL_AES_KEY_PATH);
return ret;
}
printf("Found potential Encrypted AES Key: KAES:0x%08x len:%d\n",
*(u32*)value, key_len);
/* Decypt delegates aes key using ROE */
u8* ek_iv = NULL;
bcm_sec_get_root_aes_key(&ek_iv);
key_data = malloc(key_len);
if (!key_data) {
printf("ERROR: Cannot allocate memory for decoded delegated key!\n");
return -1;
}
memcpy(key_data, (u8*)value, key_len);
debug("Decrypting del_enc_key: ROE:0x%08x, KAES:0x%08x len:%d\n",
*(u32*)ek_iv, *(u32*)value, key_len);
bcm_sec_aes_cbc128((u8*)ek_iv, (u8*)ek_iv + AES128_KEY_LENGTH, key_data, key_len,0);
/* Copy key to our delg config */
memcpy(delg_cfg->aes_ek, (void*)key_data,
BCM_SECBT_AES_CBC128_EK_LEN);
memcpy(delg_cfg->aes_ek + BCM_SECBT_AES_CBC128_EK_LEN,
(void*)(key_data+BCM_SECBT_AES_CBC128_EK_LEN), BCM_SECBT_AES_CBC128_EK_LEN);
free(key_data);
key_data = NULL;
debug("Decrypted AES_EK: 0x%08x AES_IV: 0x%08x\n",
*(u32*)delg_cfg->aes_ek,
*(u32*)(delg_cfg->aes_ek + BCM_SECBT_AES_CBC128_EK_LEN));
bcm_sec_set_active_aes_key(delg_cfg->aes_ek);
/* Save our pointer to our policy for later use */
delg_cfg->sec_policy_fit = policy_fdt;
/* TODO:Handle sec restrictions */
bcm_sec_delg_pre_process_restrictions(policy_fdt, fit_hdr);
ret = 0;
return ret;
}
int bcm_sec_delg_process_sec_node(u8 * fit)
{
size_t size = 0;
int nodeoffset = 0;
ulong * sec_policy_ptr = NULL;
u8 * sig_sec_fit_delg = NULL;
int sig_len = 0;
int ret = -1;
u8* krot_pub = bcm_sec_get_root_pub_key();
struct image_sign_info im;
/* Setup signing structures */
im.checksum = image_get_checksum_algo("sha256,");
if (!im.checksum) {
printf("ERROR: couldn't get checksum algo\n");
return ret;
}
nodeoffset = fdt_path_offset((void *)fit, DELG_SEC_FIT_NODE_PATH);
if( nodeoffset < 0 ) {
printf("ERROR: %s node not found in FIT!\n", DELG_SEC_FIT_NODE_PATH);
return ret;
}
/* Get security policy dtb */
fit_image_get_data_and_size((void *)fit, nodeoffset, (const void**)&sec_policy_ptr, &size);
if( !size ) {
printf("ERROR: sec policy data not found!\n");
return ret;
}
/* Get signature */
sig_sec_fit_delg = (u8*)fdt_getprop( (void *)fit, nodeoffset, DELG_SEC_FIT_NODE_SIG, &sig_len);
if( !sig_sec_fit_delg) {
printf("ERROR: %s not found in %s !\n", DELG_SEC_FIT_NODE_SIG,
DELG_SEC_FIT_NODE_PATH);
return ret;
}
/* Verify signature */
printf("Found potential Security Node: Policy:0x%08x Sig:0x%08x Size:%d\n",
*(u32*)sec_policy_ptr, *(u32*)sig_sec_fit_delg, (u32)size);
ret = bcm_sec_rsa_verify((u8*)sec_policy_ptr,
size,
sig_sec_fit_delg,
RSA2048_BYTES, krot_pub, &im );
if( ret == 0 ) {
printf("Security Node Authentication Successfull!\n");
/* Process policy */
ret = bcm_sec_delg_process_policy((u8*)sec_policy_ptr, fit);
} else {
printf("ERROR: Security Node Authentication FAILS!");
ret = -1;
}
return ret;
}
int bcm_sec_delg_process_sdr( u8 * psdr, u8 * hdr_end, u32 * sdr_plus_sig_size)
{
int rc = -1;
u32 lvl = 0;
u32 delegateId = 0;
u32 max_anti_rollback_lvl = 0;
u8* sdr_start = psdr;
unsigned long long sdr_size = 0;
u8* sig_sec_rec_delg = NULL;
u8* krsa_delg_pub = NULL;
u8* krot_pub = bcm_sec_get_root_pub_key();
struct image_sign_info im;
bcm_sec_delg_cfg * delg_cfg = NULL;
/* Setup signing structures */
im.checksum = image_get_checksum_algo("sha256,");
if (!im.checksum) {
printf("ERROR: couldn't get checksum algo\n");
goto err;
}
/* parse sdr fields */
psdr += sizeof(u32);
delegateId = *(u32*)psdr;
psdr += sizeof(u32);
max_anti_rollback_lvl = *(u32*)psdr;
psdr += sizeof(u32);
krsa_delg_pub = psdr;
psdr += RSA2048_BYTES;
sig_sec_rec_delg = psdr;
sdr_size = (unsigned long long )(psdr - sdr_start); // Check this
*sdr_plus_sig_size = sdr_size + RSA2048_BYTES;
printf("Found potential SDR: delg_id:%d maxrollbck:%d size:%llu\n",
delegateId, max_anti_rollback_lvl, sdr_size);
printf("Found potential SDR: PubKey:0x%08x Sig:0x%08x\n",
*(u32*)krsa_delg_pub, *(u32*)sig_sec_rec_delg);
/* Check if SDR + signature have crossed our search boundary */
if ( ((u8*)psdr + *sdr_plus_sig_size-1) > hdr_end ) {
printf("ERROR: Corrupted SDR, search exceeds boundary 0x%p > 0x%p\n",
(u8*)psdr + RSA2048_BYTES-1, hdr_end);
goto err;
}
/* Check if delegateID is valid */
if( !delegateId ) {
printf("ERROR: Invalid Delegate ID %d\n", delegateId);
goto err;
}
/* Check if anti-rollback is valid */
rc = bcm_sec_get_antirollback_lvl(&lvl);
if( (lvl > max_anti_rollback_lvl) || rc ) {
printf("ERROR: Expired delegated credentials detected curr(%d) > max(%d) rc:%d\n",
lvl, max_anti_rollback_lvl, rc);
rc = -1;
goto err;
}
/* Authenticate sdr signature */
rc = bcm_sec_rsa_verify(sdr_start,
sdr_size,
sig_sec_rec_delg,
RSA2048_BYTES, krot_pub, &im );
if( rc == 0 ) {
printf("SDR Authentication Successfull!\n");
/* Commit all fields to our structures */
delg_cfg = malloc(sizeof(bcm_sec_delg_cfg)); //TODO: Where to free this?
if (!delg_cfg) {
printf("ERROR: Cannot allocate memory for delegation config!\n");
rc = -1;
goto err;
}
delg_cfg->delg_id = delegateId;
delg_cfg->max_antirollback = max_anti_rollback_lvl;
memcpy(delg_cfg->rsa_pub, krsa_delg_pub, BCM_SECBT_RSA2048_MOD_LEN);
/* Commit delegation config */
bcm_sec_set_delg_cfg( delg_cfg );
/* Set active public key */
bcm_sec_set_active_pub_key( (u8*)delg_cfg->rsa_pub );
} else {
printf("ERROR: SDR Authentication FAILS!\n");
rc = -1;
}
err:
return rc;
}
/* returns heap allocated key*/
static int fdt_key_decrypt(void* fit, int node, const char* prop,
const u8* ek_iv, u8* aes)
{
int rc = -1, len = 0;
assert(BCM_SECBT_AES_CBC128_EK_LEN == AES128_KEY_LENGTH);
const u8* key = fdt_getprop(fit, node, prop, &len);
if (!key || ((len-1)%(AES128_KEY_LENGTH*2))) {
if (key) {
printf("Error: Invalid size for %s must be at least %d including iv \n",prop ,AES128_KEY_LENGTH*2);
}
goto err;
}
if (bcm_util_hex2u32((const char*)key, aes) < 0) {
goto err;
}
bcm_sec_aes_cbc128((u8*)ek_iv, (u8*)ek_iv + AES128_KEY_LENGTH, aes, (len-1)/2, 0);
rc = 0;
err:
return rc;
}
static int bcm_sec_fit_key_chain(void* fit, int node, bcm_sec_key_arg_t** aes )
{
int rc = -1, len = 0;
u8* ek_iv = NULL;
bcm_sec_key_aes_arg_t* _aes = NULL;
bcm_sec_key_arg_t* aes_arg = NULL;
char *_keys_prop[2] = {FIT_AES1, FIT_AES2};
bcm_sec_get_active_aes_key(&ek_iv);
if (!ek_iv) {
goto err;
}
aes_arg = malloc(sizeof(bcm_sec_key_arg_t));
_aes = malloc(sizeof(bcm_sec_key_aes_arg_t)*2);
if (!aes_arg || !_aes) {
goto err;
}
memset(aes_arg, 0, sizeof(bcm_sec_key_arg_t));
memset(_aes, 0, sizeof(bcm_sec_key_arg_t)*2);
aes_arg->aes = _aes;
if (fdt_key_decrypt(fit, node, _keys_prop[0], ek_iv, _aes[0].key)) {
free(_aes);
free(aes_arg);
goto err;
}
strcpy(_aes[0].id, _keys_prop[0]);
aes_arg->len++;
if (!fdt_key_decrypt(fit, node, _keys_prop[1], _aes[0].key, _aes[1].key)) {
if (fdt_getprop(fit, node, "dont-flush-aes1", &len)) {
/* will chain aes1-key along with dev key */
strcpy(_aes[1].id, _keys_prop[1]);
aes_arg->len++;
} else {
strcpy(_aes[0].id, _keys_prop[1]);
memcpy(_aes[0].key, _aes[1].key, AES128_KEY_LENGTH*2);
memset(_aes[1].key, AES128_KEY_LENGTH*2, 0);
}
}
*aes = aes_arg;
rc = 0;
err:
return rc;
}
static int bcm_sec_set_sotp_hw_state(u8* fit, int node, bcm_sec_cb_arg_t* sotp_st_arg) {
int * value = NULL;
int len;
/* Set sotp hardware state */
value = (int*)fdt_getprop(fit, node, "sotp-lock", &len);
if( value ) {
if (strncmp((const char*)value, "all", 3) == 0) {
/* Lock access for all masters */
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_LOCK_ALL;
} else if( strncmp((const char*)value, "none", 4) == 0 ) {
/* Lock access for none ( unlocked for all masters ) */
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_UNLOCK_SOTP_UNSEC;
} else if( strncmp((const char*)value, "prov", 4) == 0 ) {
/* Provisioning mode, Lock access for none, lock non-zero rows */
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_UNLOCK_SOTP_UNSEC_PROV;
} else {
/* Lock access for non secure masters only ( unlocked for secure masters only )*/
sotp_st_arg->arg[0].ctrl = SEC_CTRL_SOTP_UNLOCK_SOTP_SEC;
}
}
return 0;
}
static int bcm_sec_set_rng_hw_state(u8* fit, int node, bcm_sec_cb_arg_t* rng_st_arg) {
int * value = NULL;
int len;
/* Set rng hardware state */
value = (int*)fdt_getprop(fit, node, "rng-lock", &len);
if( value ) {
if(strncmp((const char*)value, "all", 3) == 0) {
/* Lock access for all masters */
rng_st_arg->arg[0].ctrl = SEC_CTRL_RNG_LOCK_ALL;
} else if( strncmp((const char*)value, "none", 4) == 0 ) {
/* Lock access for none ( unlocked for all masters ) */
rng_st_arg->arg[0].ctrl = SEC_CTRL_RNG_UNLOCK_RNG_UNSEC;
} else {
/* Lock access for non secure masters only ( unlocked for secure masters only )*/
rng_st_arg->arg[0].ctrl = SEC_CTRL_RNG_UNLOCK_RNG_SEC;
}
}
return 0;
}
int bcm_sec_fit(void* fit)
{
bcm_sec_key_arg_t *aes;
int node = -1;
/*trust/dont-lock-sotp ==> otherwise, lock SOTP before passing control
trust/dont-flush-aes1 ==> otherwise, wipe out the aes key before passing control
trust/aes1-key = hex-string ==> use original AES key to decrypt this string, wipe the original key,*/
bcm_sec_cb_arg_t cb_args[SEC_CTRL_ARG_MAX] = {0};
bcm_sec_cb_arg_t* karg = &cb_args[SEC_CTRL_ARG_KEY];
bcm_sec_cb_arg_t* sarg = &cb_args[SEC_CTRL_ARG_SOTP];
bcm_sec_cb_arg_t* rarg = &cb_args[SEC_CTRL_ARG_RNG];
bcm_sec_delg_cfg* delg_cfg = bcm_sec_get_delg_cfg();
/* Chain keys if required */
/* when enumerated later 0 - will be run first
* 1- second and so on.for both s_ctrl and k_ctrl
*/
karg->arg[0].ctrl = SEC_CTRL_KEY_CHAIN_RSA;
karg->arg[3].ctrl = SEC_CTRL_KEY_CLEAN_ALL;
if( delg_cfg && delg_cfg->delg_id ) {
/* If delegated credentials are in play then do not pass aes1/aes2
* and instead process encoded keys in FIT and security node */
bcm_sec_process_encoded_keys(fit, karg);
} else {
node = fdt_path_offset (fit, "/trust");
if (node < 0) {
/* No trust node */
goto done;
}
/* aes1 aka aes1
* aes2 gets decrypted by aes1, aes1 gets decrypted by ROE aka truste bootrom key
* */
if (!bcm_sec_fit_key_chain(fit, node, &aes)) {
karg->arg[1].ctrl = SEC_CTRL_KEY_CHAIN_AES;
karg->arg[1].ctrl_arg = aes;
}
}
/* Configure anti-rollback levels */
bcm_sec_process_antirollback(fit);
/* Export secure items */
bcm_sec_process_exports(fit, karg);
done:
/* Set hw states */
bcm_sec_process_hw_state(fit, sarg, rarg);
bcm_sec_do(SEC_SET_SCHED, cb_args);
return 0;
}
|