1 /*
2 * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "soc/chip_revision.h"
8 #include "hal/efuse_hal.h"
9 #include "esp_efuse.h"
10 #include "esp_efuse_utility.h"
11 #include "soc/efuse_periph.h"
12 #include "assert.h"
13 #include "sdkconfig.h"
14 #include "esp_efuse_table.h"
15
16 /*
17 * Each eFuse key block has a special field that defines the purpose of this block.
18 * This special field is called key_purpose.
19 */
20
21 const static char *TAG = "efuse";
22
23 /**
24 * @brief Keys and their attributes are packed into a structure
25 */
26 typedef struct {
27 const esp_efuse_desc_t** key; /**< Key */
28 const esp_efuse_desc_t** keypurpose; /**< Key purpose */
29 const esp_efuse_desc_t** key_rd_dis; /**< Read protection of a key */
30 const esp_efuse_desc_t** key_wr_dis; /**< Write protection of a key*/
31 const esp_efuse_desc_t** keypurpose_wr_dis; /**< Write protection of a key purpose*/
32 } esp_efuse_keys_t;
33
34 typedef struct {
35 const esp_efuse_desc_t** revoke;
36 const esp_efuse_desc_t** revoke_wr_dis;
37 const esp_efuse_purpose_t digest_purpose;
38 } esp_efuse_revokes_t;
39
40 const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = {
41 {ESP_EFUSE_KEY0, ESP_EFUSE_KEY_PURPOSE_0, ESP_EFUSE_RD_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0, ESP_EFUSE_WR_DIS_KEY0_PURPOSE},
42 {ESP_EFUSE_KEY1, ESP_EFUSE_KEY_PURPOSE_1, ESP_EFUSE_RD_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1, ESP_EFUSE_WR_DIS_KEY1_PURPOSE},
43 {ESP_EFUSE_KEY2, ESP_EFUSE_KEY_PURPOSE_2, ESP_EFUSE_RD_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2, ESP_EFUSE_WR_DIS_KEY2_PURPOSE},
44 {ESP_EFUSE_KEY3, ESP_EFUSE_KEY_PURPOSE_3, ESP_EFUSE_RD_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3, ESP_EFUSE_WR_DIS_KEY3_PURPOSE},
45 {ESP_EFUSE_KEY4, ESP_EFUSE_KEY_PURPOSE_4, ESP_EFUSE_RD_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4, ESP_EFUSE_WR_DIS_KEY4_PURPOSE},
46 {ESP_EFUSE_KEY5, ESP_EFUSE_KEY_PURPOSE_5, ESP_EFUSE_RD_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5, ESP_EFUSE_WR_DIS_KEY5_PURPOSE},
47 #if 0
48 {ESP_EFUSE_KEY6, ESP_EFUSE_KEY_PURPOSE_6, ESP_EFUSE_RD_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6, ESP_EFUSE_WR_DIS_KEY6_PURPOSE},
49 #endif
50 };
51
52 #if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
53 const esp_efuse_revokes_t s_revoke_table[] = {
54 {ESP_EFUSE_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE0, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0},
55 {ESP_EFUSE_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE1, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1},
56 {ESP_EFUSE_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_WR_DIS_SECURE_BOOT_KEY_REVOKE2, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2},
57 };
58 #endif
esp_efuse_block_is_empty(esp_efuse_block_t block)59 bool esp_efuse_block_is_empty(esp_efuse_block_t block)
60 {
61 const unsigned blk_len_bit = 256;
62 uint32_t key[8];
63 esp_err_t err = esp_efuse_read_block(block, &key, 0, blk_len_bit);
64 if (err != ESP_OK) {
65 return false;
66 }
67 unsigned zeros = 0;
68 for (unsigned i = 0; i < blk_len_bit / 32; ++i) {
69 if (key[i] == 0) {
70 ++zeros;
71 }
72 }
73 if (zeros == blk_len_bit / 32) {
74 return true;
75 }
76 return false;
77 }
78
79 // Sets a write protection for the whole block.
esp_efuse_set_write_protect(esp_efuse_block_t blk)80 esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk)
81 {
82 if (blk == EFUSE_BLK1) {
83 return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_BLK1, 1);
84 } else if (blk == EFUSE_BLK2) {
85 return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART1, 1);
86 } else if (blk == EFUSE_BLK3) {
87 return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_USER_DATA, 1);
88 } else if (blk == EFUSE_BLK10) {
89 return esp_efuse_write_field_cnt(ESP_EFUSE_WR_DIS_SYS_DATA_PART2, 1);
90 } else if (blk >= EFUSE_BLK_KEY0 && blk < EFUSE_BLK_KEY_MAX) {
91 unsigned idx = blk - EFUSE_BLK_KEY0;
92 return esp_efuse_write_field_cnt(s_table[idx].key_wr_dis, 1);
93 }
94 return ESP_ERR_NOT_SUPPORTED;
95 }
96
97 // read protect for blk.
esp_efuse_set_read_protect(esp_efuse_block_t blk)98 esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk)
99 {
100 if (blk >= EFUSE_BLK_KEY0 && blk < EFUSE_BLK_KEY_MAX) {
101 unsigned idx = blk - EFUSE_BLK_KEY0;
102 return esp_efuse_write_field_cnt(s_table[idx].key_rd_dis, 1);
103 }
104 else if (blk == EFUSE_BLK10) {
105 return esp_efuse_write_field_cnt(ESP_EFUSE_RD_DIS_SYS_DATA_PART2, 1);
106 }
107 return ESP_ERR_NOT_SUPPORTED;
108
109 }
110
111 // get efuse coding_scheme.
esp_efuse_get_coding_scheme(esp_efuse_block_t blk)112 esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk)
113 {
114 esp_efuse_coding_scheme_t scheme;
115 if (blk == EFUSE_BLK0) {
116 scheme = EFUSE_CODING_SCHEME_NONE;
117 } else {
118 scheme = EFUSE_CODING_SCHEME_RS;
119 }
120 return scheme;
121 }
122
esp_efuse_get_purpose_field(esp_efuse_block_t block)123 const esp_efuse_desc_t **esp_efuse_get_purpose_field(esp_efuse_block_t block)
124 {
125 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
126 return NULL;
127 }
128 unsigned idx = block - EFUSE_BLK_KEY0;
129 return s_table[idx].keypurpose;
130 }
131
esp_efuse_get_key(esp_efuse_block_t block)132 const esp_efuse_desc_t** esp_efuse_get_key(esp_efuse_block_t block)
133 {
134 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
135 return NULL;
136 }
137 unsigned idx = block - EFUSE_BLK_KEY0;
138 return s_table[idx].key;
139 }
140
esp_efuse_get_key_dis_read(esp_efuse_block_t block)141 bool esp_efuse_get_key_dis_read(esp_efuse_block_t block)
142 {
143 assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
144 unsigned idx = block - EFUSE_BLK_KEY0;
145 return esp_efuse_read_field_bit(s_table[idx].key_rd_dis);
146 }
147
esp_efuse_set_key_dis_read(esp_efuse_block_t block)148 esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block)
149 {
150 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
151 return ESP_ERR_INVALID_ARG;
152 }
153 unsigned idx = block - EFUSE_BLK_KEY0;
154 return esp_efuse_write_field_bit(s_table[idx].key_rd_dis);
155 }
156
esp_efuse_get_key_dis_write(esp_efuse_block_t block)157 bool esp_efuse_get_key_dis_write(esp_efuse_block_t block)
158 {
159 assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
160 unsigned idx = block - EFUSE_BLK_KEY0;
161 return esp_efuse_read_field_bit(s_table[idx].key_wr_dis);
162 }
163
esp_efuse_set_key_dis_write(esp_efuse_block_t block)164 esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block)
165 {
166 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
167 return ESP_ERR_INVALID_ARG;
168 }
169 unsigned idx = block - EFUSE_BLK_KEY0;
170 return esp_efuse_write_field_bit(s_table[idx].key_wr_dis);
171 }
172
esp_efuse_get_key_purpose(esp_efuse_block_t block)173 esp_efuse_purpose_t esp_efuse_get_key_purpose(esp_efuse_block_t block)
174 {
175 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
176 return ESP_EFUSE_KEY_PURPOSE_MAX;
177 }
178 unsigned idx = block - EFUSE_BLK_KEY0;
179 uint8_t value = 0;
180 esp_err_t err = esp_efuse_read_field_blob(s_table[idx].keypurpose, &value, s_table[idx].keypurpose[0]->bit_count);
181 if (err != ESP_OK) {
182 return ESP_EFUSE_KEY_PURPOSE_MAX;
183 }
184 return value;
185 }
186
esp_efuse_set_key_purpose(esp_efuse_block_t block,esp_efuse_purpose_t purpose)187 esp_err_t esp_efuse_set_key_purpose(esp_efuse_block_t block, esp_efuse_purpose_t purpose)
188 {
189 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
190 return ESP_ERR_INVALID_ARG;
191 }
192 unsigned idx = block - EFUSE_BLK_KEY0;
193 return esp_efuse_write_field_blob(s_table[idx].keypurpose, &purpose, s_table[idx].keypurpose[0]->bit_count);
194 }
195
esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block)196 bool esp_efuse_get_keypurpose_dis_write(esp_efuse_block_t block)
197 {
198 assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX);
199 unsigned idx = block - EFUSE_BLK_KEY0;
200 return esp_efuse_read_field_bit(s_table[idx].keypurpose_wr_dis);
201 }
202
esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block)203 esp_err_t esp_efuse_set_keypurpose_dis_write(esp_efuse_block_t block)
204 {
205 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
206 return ESP_ERR_INVALID_ARG;
207 }
208 unsigned idx = block - EFUSE_BLK_KEY0;
209 return esp_efuse_write_field_bit(s_table[idx].keypurpose_wr_dis);
210 }
211
esp_efuse_find_purpose(esp_efuse_purpose_t purpose,esp_efuse_block_t * block)212 bool esp_efuse_find_purpose(esp_efuse_purpose_t purpose, esp_efuse_block_t *block)
213 {
214 esp_efuse_block_t dummy;
215 if (block == NULL) {
216 block = &dummy;
217 }
218
219 for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
220 if (esp_efuse_get_key_purpose(b) == purpose) {
221 *block = b;
222 return true;
223 }
224 }
225
226 return false;
227 }
228
esp_efuse_find_unused_key_block(void)229 esp_efuse_block_t esp_efuse_find_unused_key_block(void)
230 {
231 for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
232 if (esp_efuse_key_block_unused(b)) {
233 return b;
234 }
235 }
236 return EFUSE_BLK_KEY_MAX; // nothing
237 }
238
esp_efuse_count_unused_key_blocks(void)239 unsigned esp_efuse_count_unused_key_blocks(void)
240 {
241 unsigned r = 0;
242 for (esp_efuse_block_t b = EFUSE_BLK_KEY0; b < EFUSE_BLK_KEY_MAX; b++) {
243 if (esp_efuse_key_block_unused(b)) {
244 r++;
245 }
246 }
247 return r;
248 }
249
esp_efuse_key_block_unused(esp_efuse_block_t block)250 bool esp_efuse_key_block_unused(esp_efuse_block_t block)
251 {
252 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) {
253 return false; // Not a key block
254 }
255
256 if (esp_efuse_get_key_purpose(block) != ESP_EFUSE_KEY_PURPOSE_USER ||
257 esp_efuse_get_keypurpose_dis_write(block) ||
258 esp_efuse_get_key_dis_read(block) ||
259 esp_efuse_get_key_dis_write(block)) {
260 return false; // Block in use!
261 }
262
263 if (!esp_efuse_block_is_empty(block)) {
264 return false; // Block in use!
265 }
266
267 return true; // Unused
268 }
269
esp_efuse_write_key(esp_efuse_block_t block,esp_efuse_purpose_t purpose,const void * key,size_t key_size_bytes)270 esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpose, const void *key, size_t key_size_bytes)
271 {
272 esp_err_t err = ESP_OK;
273
274 if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX || key_size_bytes > 32 || purpose >= ESP_EFUSE_KEY_PURPOSE_MAX) {
275 return ESP_ERR_INVALID_ARG;
276 }
277
278 esp_efuse_batch_write_begin();
279
280 if (!esp_efuse_key_block_unused(block)) {
281 err = ESP_ERR_INVALID_STATE;
282 } else {
283 unsigned idx = block - EFUSE_BLK_KEY0;
284 ESP_EFUSE_CHK(esp_efuse_write_field_blob(s_table[idx].key, key, key_size_bytes * 8));
285 ESP_EFUSE_CHK(esp_efuse_set_key_dis_write(block));
286
287 #if SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK
288 if (block == EFUSE_BLK9 && (
289 #if SOC_FLASH_ENCRYPTION_XTS_AES_256
290 purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
291 purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
292 #endif
293 #if SOC_ECDSA_SUPPORTED
294 purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY ||
295 #endif
296 purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY)) {
297 ESP_LOGE(TAG, "BLOCK9 can not have the %d purpose because of HW bug (see TRM for more details)", purpose);
298 err = ESP_ERR_NOT_SUPPORTED;
299 goto err_exit;
300 }
301 #endif // SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK
302
303 if (purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY ||
304 #ifdef SOC_FLASH_ENCRYPTION_XTS_AES_256
305 purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 ||
306 purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 ||
307 #endif //#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS
308 #if SOC_ECDSA_SUPPORTED
309 purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY ||
310 #endif
311 purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL ||
312 purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG ||
313 purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE ||
314 purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
315 ESP_EFUSE_CHK(esp_efuse_set_key_dis_read(block));
316 }
317 #if SOC_EFUSE_ECDSA_USE_HARDWARE_K
318 if (purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY) {
319 // Permanently enable the hardware TRNG supplied k mode (most secure mode)
320 if (!CONFIG_IDF_TARGET_ESP32H2 || (CONFIG_IDF_TARGET_ESP32H2 && !ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102))) {
321 ESP_EFUSE_CHK(esp_efuse_write_field_bit(ESP_EFUSE_ECDSA_FORCE_USE_HARDWARE_K));
322 }
323 }
324 #endif
325 ESP_EFUSE_CHK(esp_efuse_set_key_purpose(block, purpose));
326 ESP_EFUSE_CHK(esp_efuse_set_keypurpose_dis_write(block));
327 return esp_efuse_batch_write_commit();
328 }
329 err_exit:
330 esp_efuse_batch_write_cancel();
331 return err;
332 }
333
esp_efuse_write_keys(const esp_efuse_purpose_t purposes[],uint8_t keys[][32],unsigned number_of_keys)334 esp_err_t esp_efuse_write_keys(const esp_efuse_purpose_t purposes[], uint8_t keys[][32], unsigned number_of_keys)
335 {
336 esp_err_t err = ESP_OK;
337 if (number_of_keys == 0 || number_of_keys > (EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0) || keys == NULL || purposes == NULL) {
338 return ESP_ERR_INVALID_ARG;
339 }
340
341 esp_efuse_purpose_t purpose = 0;
342 esp_efuse_block_t block = EFUSE_BLK_KEY0;
343
344 esp_efuse_batch_write_begin();
345
346 unsigned unused_keys = esp_efuse_count_unused_key_blocks();
347 if (number_of_keys > unused_keys) {
348 ESP_LOGE(TAG, "Not enough unused key blocks available. Required %d, was %d", number_of_keys, unused_keys);
349 err = ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS;
350 } else {
351 for (int i_key = 0; (block < EFUSE_BLK_KEY_MAX) && (i_key < number_of_keys); block++) {
352 if (esp_efuse_key_block_unused(block)) {
353 purpose = purposes[i_key];
354 ESP_LOGI(TAG, "Writing EFUSE_BLK_KEY%d with purpose %d", block - EFUSE_BLK_KEY0, purpose);
355 ESP_EFUSE_CHK(esp_efuse_write_key(block, purpose, keys[i_key], 32));
356 i_key++;
357 }
358 }
359 return esp_efuse_batch_write_commit();
360 err_exit:
361 ESP_LOGE(TAG, "Failed to write EFUSE_BLK_KEY%d with purpose %d. Can't continue.", block - EFUSE_BLK_KEY0, purpose);
362 }
363 esp_efuse_batch_write_cancel();
364 return err;
365 }
366
367
368 #if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
esp_efuse_get_digest_revoke(unsigned num_digest)369 bool esp_efuse_get_digest_revoke(unsigned num_digest)
370 {
371 assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
372 return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke);
373 }
374
esp_efuse_set_digest_revoke(unsigned num_digest)375 esp_err_t esp_efuse_set_digest_revoke(unsigned num_digest)
376 {
377 if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
378 return ESP_ERR_INVALID_ARG;
379 }
380 return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke);
381 }
382
esp_efuse_get_write_protect_of_digest_revoke(unsigned num_digest)383 bool esp_efuse_get_write_protect_of_digest_revoke(unsigned num_digest)
384 {
385 assert(num_digest < sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t));
386 return esp_efuse_read_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
387 }
388
esp_efuse_set_write_protect_of_digest_revoke(unsigned num_digest)389 esp_err_t esp_efuse_set_write_protect_of_digest_revoke(unsigned num_digest)
390 {
391 if (num_digest >= sizeof(s_revoke_table) / sizeof(esp_efuse_revokes_t)) {
392 return ESP_ERR_INVALID_ARG;
393 }
394 return esp_efuse_write_field_bit(s_revoke_table[num_digest].revoke_wr_dis);
395 }
396
esp_secure_boot_read_key_digests(esp_secure_boot_key_digests_t * trusted_keys)397 esp_err_t esp_secure_boot_read_key_digests(esp_secure_boot_key_digests_t *trusted_keys)
398 {
399 bool found = false;
400 esp_efuse_block_t key_block;
401
402 if (trusted_keys == NULL) {
403 return ESP_FAIL;
404 }
405
406 for (unsigned i = 0; i < SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS; i++) {
407 trusted_keys->key_digests[i] = NULL;
408 if (esp_efuse_get_digest_revoke(i)) {
409 continue;
410 }
411
412 // Anti-FI check that this efuse really is not revoked
413 assert(esp_efuse_get_digest_revoke(i) == 0);
414
415 if (!esp_efuse_find_purpose(s_revoke_table[i].digest_purpose, &key_block)) {
416 continue;
417 }
418 trusted_keys->key_digests[i] = (const void *)esp_efuse_utility_get_read_register_address(key_block);
419 found = found || (trusted_keys->key_digests[i] != NULL);
420 }
421
422 if (!found) {
423 return ESP_FAIL;
424 }
425
426 return ESP_OK;
427 }
428 #endif //#if SOC_SUPPORT_SECURE_BOOT_REVOKE_KEY
429