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
|
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2020 Broadcom Corporation
* Joel Peshkin, Broadcom Corporation, joel.peshkin@broadcom.com
*/
#define DEBUG
#define USE_FIXED_PASSWORD 1
#include <common.h>
#include <command.h>
#include <environment.h>
#include <hexdump.h>
#include <linux/ctype.h>
#include <linux/stddef.h>
#include <u-boot/sha256.h>
#include <errno.h>
#include <bca_sdk.h>
DECLARE_GLOBAL_DATA_PTR;
static const char *null_env = "\0\0\0\0";
#define BCM_LOCKDOWN_MAX_ENV_NAME 64
#define BCM_LOCKDOWN_MAX_ENV_VALUE 520
/* also limit with CONFIG_ENV_SIZE */
static void lock_env_add_safe(char *name, char *val, char *safe, int max);
/*
* lock_env_add_safe: Add environment variable only if its value is strictly alphanumeric or
* alphanumeric plus a specific set of characters
*/
static void lock_env_add_safe(char *name, char *val, char *safe, int max)
{
int l;
int i;
char v[2];
v[1] = '\0';
l = strlen(val);
if (l > max) {
return;
}
for (i = 0; i < l; i++) {
v[0] = val[i];
if (!(isalnum(val[i]) || (NULL != strstr(safe, v)))) {
/* printf("rejected '%s'='%s'\n",name,val); */
return;
}
}
env_set(name, val);
}
int env_override_import(void *ep)
{
char sha_env_str[SHA256_SUM_LEN * 4 + 1]; /* enough room for salt */
char password[32];
char salt[32] = {0};
char dnum[16] = {0};
u8 sha_env[SHA256_SUM_LEN];
char *cp = ((char *)ep) + 4; /* skip length field */
char *delim;
int once = 0;
int size = 0;
int i,j;
int node,len;
env_import((void *)null_env, 0);
env_set("overridden", "true");
/* Iterate over stored environment variables and only import them if they are trusted */
while (*cp != '\0') {
delim = strstr(cp, "=");
if (delim && (delim <= cp + BCM_LOCKDOWN_MAX_ENV_NAME)
&& (delim <= ep + CONFIG_ENV_SIZE)) {
*delim = '\0';
delim++;
if (strlen(delim) > BCM_LOCKDOWN_MAX_ENV_VALUE) {
break;
}
/* if we made it this far, *cp and *delim point to name and value */
if ((strcmp(cp, "IMAGE") == 0)
|| (strcmp(cp, "MCB") == 0)
|| (strcmp(cp, "ethaddr") == 0)) {
/* These are OK as long as they contain only alphanumeric plus : */
lock_env_add_safe(cp, delim, ":,", 32);
} else if (strcmp(cp, "env_boot_magic") == 0) {
/* env_boot_magic is safe but can have '@' */
lock_env_add_safe(cp, delim, "@,", 32);
} else if (strcmp(cp, "once") == 0) {
/* "once" can be stores as "once=true"
* otherwise, we will need to set it to a fixed script later
*/
if (strcmp(delim, "true") == 0) {
once = 1;
env_set(cp, delim);
}
} else if (strncmp(cp, "rdp", 3) == 0) {
lock_env_add_safe(cp, delim, "", 6);
} else if (strcmp(cp, "nummacaddrs") == 0) {
lock_env_add_safe(cp, delim, "_", 32);
} else if (strcmp(cp, "boardid") == 0) {
lock_env_add_safe(cp, delim, "_", 32);
} else {
/* printf("skipped '%s'='%s'\n",cp,delim); */
}
/* done with conditional import */
cp = delim + strlen(delim) + 1;
} else {
break;
}
}
/* Boot command can only be set from this (signed) code and will not accept arbitrary values */
env_set("bootdelay", "5");
env_set("bootcmd", "printenv; run once ; sdk boot_img");
/* If we haven't stored the value of "once" as "true" yet, we want it to be a script of commands
* to be executed once. At a minimum, after an image is programmed, we need to save the environment
* including the env_boot_magic variable one time to reflect the physical flash offset of the environment
* redundant copies
*/
if (once == 0) {
env_set("once", "setenv once true; saveenv");
}
// gd->flags |= GD_FLG_DISABLE_CONSOLE;
node = fdt_path_offset(gd->fdt_blob, "/trust/serial_num");
if (node < 0) {
printf("no serial number node in uboot DTB\n");
} else {
unsigned long sn = 0;
len = 0;
cp = NULL;
cp = (char *)fdt_getprop(gd->fdt_blob, node, "value", &len);
printf("full serial number: ");
for (i = 0; i < len ; i++) {
printf("%02x",cp[i]);
}
printf("\n");
if (len) {
for (i = 0 ; i < 6 ; i++) {
sn = (sn << 8) | (long)(cp[len-6+i]);
}
printf("decimal serial number: %ld\n",sn);
sprintf(dnum,"%ld",sn);
env_set("decimal_serial_num", dnum);
}
}
/* Now set bootstopkeysha256 */
/* In this example, password is being set to a fixed value. More likely, you will want to set it to
* something like the base64 of the last 6 bytes of the sha256 of a secret concatenated with the serial
* number
*/
size = SHA256_SUM_LEN;
j = 0;
node = fdt_path_offset(gd->fdt_blob, "/trust/key_cli_seed");
#ifndef USE_FIXED_PASSWORD
if (node < 0) {
printf("no cli seed node in uboot DTB\n");
} else {
char combined[256];
long long pass;
char cset[] = "abcdefghijk#mnopqrstuvwxyzABCDEFGHIJKLMN-PQRSTUVWXYZ@!23456789_*";
len = 0;
cp = NULL;
cp = (char *)fdt_getprop(gd->fdt_blob, node, "value", &len);
strncpy(combined,cp,256);
strncat(combined,dnum,256);
hash_block("sha256", (const void *)combined,
strlen(combined), sha_env, &size);
memcpy(&pass, sha_env, sizeof(pass));
for (i = 0 ; i < 8 ; i++) {
password[i] = cset[ (pass >> (6 * i) ) & 0x3f ];
}
password[8] = 0;
printf("OBVIOUSLY -- REMOVE THIS PRINT\npassword set to %s\n",password);
}
#endif
#ifdef USE_FIXED_PASSWORD
strcpy(salt, "S4lt3d@");
strcpy(password, salt);
strcat(password, "test54321");
#endif
hash_block("sha256", (const void *)password,
strlen(password), sha_env, &size);
j = sprintf(sha_env_str,"%s:",salt);
for (i = 0; i < SHA256_SUM_LEN; i++) {
j += sprintf(&sha_env_str[j], "%02x", sha_env[i]);
}
env_set("bootstopkeysha256", sha_env_str);
return 1;
}
|