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