This commit is contained in:
2026-02-27 22:17:33 +01:00
commit 8e95149d8e
27 changed files with 4480 additions and 0 deletions

418
main/atecc608a.h Normal file
View File

@@ -0,0 +1,418 @@
#ifndef ATECC608B_H
#define ATECC608B_H
#include "cryptoauthlib.h"
#include "sdkconfig.h"
#include <cJSON.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
static const char *TAG_ATECC = "ATECC608B";
// ATECC608B Configuration
ATCAIfaceCfg atecc_cfg;
bool atecc608B_init() {
ESP_LOGI(TAG_ATECC, "\n=== ATECC608B Initialization ===");
// Configure cryptoauthlib for ATECC608B - it will handle I2C initialization
atecc_cfg.iface_type = ATCA_I2C_IFACE;
atecc_cfg.devtype = ATECC608B;
atecc_cfg.atcai2c.address = CONFIG_ATCA_I2C_ADDRESS;
atecc_cfg.atcai2c.bus = 0; // I2C bus number
atecc_cfg.atcai2c.baud = CONFIG_ATCA_I2C_BAUD_RATE;
atecc_cfg.wake_delay = 1500;
atecc_cfg.rx_retries = 20;
ESP_LOGI(TAG_ATECC,
"Configuring ATECC608B: SDA=GPIO%d, SCL=GPIO%d, Address=0x%02X "
"(7-bit: 0x%02X)",
CONFIG_ATCA_I2C_SDA_PIN, CONFIG_ATCA_I2C_SCL_PIN,
CONFIG_ATCA_I2C_ADDRESS, CONFIG_ATCA_I2C_ADDRESS >> 1);
// Initialize cryptoauthlib (it will initialize I2C internally)
ATCA_STATUS status = atcab_init(&atecc_cfg);
if (status != ATCA_SUCCESS) {
ESP_LOGE(TAG_ATECC, "ERROR: atcab_init failed with status 0x%02X", status);
return false;
}
ESP_LOGI(TAG_ATECC, "ATECC608B initialized successfully");
// Give the device a moment to stabilize
vTaskDelay(pdMS_TO_TICKS(100));
// Wake the device and test communication
status = atcab_wakeup();
if (status != ATCA_SUCCESS) {
ESP_LOGW(TAG_ATECC, "WARNING: Wake command returned status 0x%02X", status);
}
// Put device to idle
atcab_idle();
vTaskDelay(pdMS_TO_TICKS(50));
return true;
}
// Global storage for config zone data
uint8_t g_atecc_config_data[128] = {0};
bool g_atecc_config_valid = false;
/**
* Read ATECC608B configuration zone into global buffer
*/
bool atecc608B_read_config() {
ESP_LOGI(TAG_ATECC, "Reading ATECC608B configuration zone...");
ATCA_STATUS status = atcab_read_config_zone(g_atecc_config_data);
if (status != ATCA_SUCCESS) {
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read config zone, status 0x%02X",
status);
// Try reading it in blocks as a workaround
ESP_LOGI(TAG_ATECC, "Attempting to read config in 4-byte blocks...");
bool read_success = true;
for (uint8_t block = 0; block < 32; block++) {
status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, block, 0,
&g_atecc_config_data[block * 4], 4);
if (status != ATCA_SUCCESS) {
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read block %d, status 0x%02X",
block, status);
read_success = false;
break;
}
}
if (!read_success) {
ESP_LOGE(TAG_ATECC, "ERROR: Could not read configuration zone");
g_atecc_config_valid = false;
return false;
}
ESP_LOGI(TAG_ATECC, "Successfully read config in blocks");
}
g_atecc_config_valid = true;
return true;
}
/**
* Print ATECC608B configuration zone to console with detailed subzone breakdown
* According to ATECC608B Table 2-4
*/
void atecc608B_print_config() {
ESP_LOGI(TAG_ATECC, "\n=== ATECC608B Configuration Zone ===");
// First, try to read the serial number as a simple communication test
uint8_t serial_number[9];
ATCA_STATUS status = atcab_read_serial_number(serial_number);
if (status != ATCA_SUCCESS) {
ESP_LOGE(TAG_ATECC, "ERROR: Failed to read serial number, status 0x%02X",
status);
ESP_LOGE(TAG_ATECC, "This might indicate a communication or wiring issue.");
return;
}
// Read configuration zone into global buffer
if (!atecc608B_read_config()) {
return;
}
uint8_t *config_data = g_atecc_config_data;
// Print complete hex dump first
ESP_LOGI(TAG_ATECC, "\n--- Complete Configuration Zone (128 bytes) ---");
for (int i = 0; i < 128; i++) {
if (i % 16 == 0) {
printf("\n0x%02X: ", i);
}
printf("%02X ", config_data[i]);
}
printf("\n");
// Print detailed subzone breakdown according to Table 2-4
ESP_LOGI(TAG_ATECC, "\n--- Subzone Breakdown (Table 2-4) ---");
// Bytes 0-3: Serial Number[0:3]
printf("\n[Bytes 0-3] Serial Number[0:3]: ");
for (int i = 0; i < 4; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Bytes 4-7: Revision Number
printf("[Bytes 4-7] Revision Number: ");
for (int i = 4; i < 8; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Bytes 8-12: Serial Number[4:8]
printf("[Bytes 8-12] Serial Number[4:8]: ");
for (int i = 8; i < 13; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Full Serial Number
printf(" --> Complete Serial Number: ");
for (int i = 0; i < 4; i++)
printf("%02X", config_data[i]);
for (int i = 8; i < 13; i++)
printf("%02X", config_data[i]);
printf("\n");
// Byte 13: Reserved
printf("[Byte 13] Reserved: %02X\n", config_data[13]);
// Byte 14: I2C_Enable
printf("[Byte 14] I2C_Enable: %02X\n", config_data[14]);
// Byte 15: Reserved
printf("[Byte 15] Reserved: %02X\n", config_data[15]);
// Byte 16: I2C_Address
printf("[Byte 16] I2C_Address: 0x%02X (7-bit: 0x%02X)\n", config_data[16],
config_data[16] >> 1);
// Byte 17: Reserved
printf("[Byte 17] Reserved: %02X\n", config_data[17]);
// Byte 18: OTPmode
printf("[Byte 18] OTPmode: 0x%02X\n", config_data[18]);
// Byte 19: ChipMode
printf("[Byte 19] ChipMode: 0x%02X ", config_data[19]);
if (config_data[19] & 0x01)
printf("[I2C_UserExtraAdd] ");
if (config_data[19] & 0x02)
printf("[TTL_Enable] ");
if (config_data[19] & 0x04)
printf("[Watchdog_1.3s] ");
printf("\n");
// Bytes 20-51: SlotConfig[0:15] (16 slots × 2 bytes)
printf("\n[Bytes 20-51] SlotConfig[0:15]:\n");
for (int slot = 0; slot < 16; slot++) {
int offset = 20 + (slot * 2);
uint8_t slot_config_low = config_data[offset];
uint8_t slot_config_high = config_data[offset + 1];
uint16_t slot_config = (slot_config_high << 8) | slot_config_low;
printf(" Slot %2d [Bytes %2d-%2d]: 0x%02X 0x%02X (", slot, offset,
offset + 1, slot_config_low, slot_config_high);
// Print 16-bit binary representation
for (int b = 15; b >= 0; b--)
printf("%d", (slot_config >> b) & 1);
printf(")");
bool is_secret = (slot_config & 0x8000) != 0;
bool encrypt_read = (slot_config & 0x4000) != 0;
if (is_secret)
printf(" [Secret]");
if (encrypt_read)
printf(" [EncryptRead]");
printf("\n");
}
// Bytes 52-59: Counter[0]
printf("\n[Bytes 52-59] Counter[0]: ");
for (int i = 52; i < 60; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Bytes 60-67: Counter[1]
printf("[Bytes 60-67] Counter[1]: ");
for (int i = 60; i < 68; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Bytes 68-83: LastKeyUse[0:15]
printf("\n[Bytes 68-83] LastKeyUse[0:15]: ");
for (int i = 68; i < 84; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Byte 84: UserExtra
printf("\n[Byte 84] UserExtra: 0x%02X\n", config_data[84]);
// Byte 85: Selector
printf("[Byte 85] Selector: 0x%02X\n", config_data[85]);
// Byte 86: LockValue (Data/OTP Zone Lock)
printf("[Byte 86] LockValue (Data/OTP): 0x%02X %s\n", config_data[86],
config_data[86] == 0x00 ? "[LOCKED]" : "[UNLOCKED]");
// Byte 87: LockConfig (Config Zone Lock)
printf("[Byte 87] LockConfig: 0x%02X %s\n", config_data[87],
config_data[87] == 0x00 ? "[LOCKED]" : "[UNLOCKED]");
// Bytes 88-89: SlotLocked
printf("\n[Bytes 88-89] SlotLocked: %02X %02X\n", config_data[88],
config_data[89]);
// Bytes 90-91: ChipOptions
printf("[Bytes 90-91] ChipOptions: ");
uint16_t chip_options = (config_data[91] << 8) | config_data[90];
printf("0x%04X\n", chip_options);
// Bytes 92-95: X509format
printf("[Bytes 92-95] X509format: ");
for (int i = 92; i < 96; i++)
printf("%02X ", config_data[i]);
printf("\n");
// Bytes 96-127: KeyConfig[0:15] (16 slots × 2 bytes)
printf("\n[Bytes 96-127] KeyConfig[0:15]:\n");
for (int slot = 0; slot < 16; slot++) {
int offset = 96 + (slot * 2);
uint8_t key_config_low = config_data[offset];
uint8_t key_config_high = config_data[offset + 1];
uint16_t key_config = (key_config_high << 8) | key_config_low;
printf(" Slot %2d [Bytes %2d-%2d]: 0x%02X 0x%02X (", slot, offset,
offset + 1, key_config_low, key_config_high);
// Print 16-bit binary representation
for (int b = 15; b >= 0; b--)
printf("%d", (key_config >> b) & 1);
printf(")");
bool is_private = (key_config & 0x0001) != 0;
if (is_private)
printf(" [Private]");
printf("\n");
}
ESP_LOGI(TAG_ATECC, "\n=== End of ATECC608B Configuration ===\n");
}
/**
* Get ATECC608B configuration as JSON string (caller must free the returned
* string)
*/
char *atecc608B_get_config_json() {
if (!g_atecc_config_valid) {
ESP_LOGE(TAG_ATECC,
"Config data not valid. Call atecc608B_print_config() first.");
return NULL;
}
uint8_t *config = g_atecc_config_data;
cJSON *root = cJSON_CreateObject();
// Add raw hex data
char hex_str[385]; // 128 bytes * 3 chars per byte + null
char *ptr = hex_str;
for (int i = 0; i < 128; i++) {
ptr += sprintf(ptr, "%02X ", config[i]);
}
cJSON_AddStringToObject(root, "raw_hex", hex_str);
// Serial Number
char serial_str[19];
sprintf(serial_str, "%02X%02X%02X%02X%02X%02X%02X%02X%02X", config[0],
config[1], config[2], config[3], config[8], config[9], config[10],
config[11], config[12]);
cJSON_AddStringToObject(root, "serial_number", serial_str);
// Revision
char revision_str[12];
sprintf(revision_str, "%02X%02X%02X%02X", config[4], config[5], config[6],
config[7]);
cJSON_AddStringToObject(root, "revision", revision_str);
// I2C settings
cJSON_AddNumberToObject(root, "i2c_enable", config[14]);
cJSON_AddNumberToObject(root, "i2c_address", config[16]);
// Mode settings
cJSON_AddNumberToObject(root, "otp_mode", config[18]);
cJSON_AddNumberToObject(root, "chip_mode", config[19]);
// Lock status
cJSON *locks = cJSON_CreateObject();
cJSON_AddBoolToObject(locks, "config_locked", config[87] == 0x00);
cJSON_AddBoolToObject(locks, "data_otp_locked", config[86] == 0x00);
cJSON_AddItemToObject(root, "locks", locks);
// Slot configurations
cJSON *slots = cJSON_CreateArray();
for (int slot = 0; slot < 16; slot++) {
cJSON *slot_obj = cJSON_CreateObject();
cJSON_AddNumberToObject(slot_obj, "slot", slot);
int slot_config_offset = 20 + (slot * 2);
uint8_t slot_config_low = config[slot_config_offset];
uint8_t slot_config_high = config[slot_config_offset + 1];
uint16_t slot_config = (slot_config_high << 8) | slot_config_low;
cJSON *slot_config_arr = cJSON_CreateArray();
char slot_config_low_str[5];
char slot_config_high_str[5];
sprintf(slot_config_low_str, "0x%02X", slot_config_low);
sprintf(slot_config_high_str, "0x%02X", slot_config_high);
cJSON_AddItemToArray(slot_config_arr,
cJSON_CreateString(slot_config_low_str));
cJSON_AddItemToArray(slot_config_arr,
cJSON_CreateString(slot_config_high_str));
cJSON_AddItemToObject(slot_obj, "slot_config", slot_config_arr);
// Add 16-bit binary representation
char slot_config_bin[18];
for (int b = 0; b < 16; b++) {
slot_config_bin[15 - b] = ((slot_config >> b) & 1) ? '1' : '0';
}
slot_config_bin[16] = '\0';
cJSON_AddStringToObject(slot_obj, "slot_config_binary", slot_config_bin);
int key_config_offset = 96 + (slot * 2);
uint8_t key_config_low = config[key_config_offset];
uint8_t key_config_high = config[key_config_offset + 1];
uint16_t key_config = (key_config_high << 8) | key_config_low;
cJSON *key_config_arr = cJSON_CreateArray();
char key_config_low_str[5];
char key_config_high_str[5];
sprintf(key_config_low_str, "0x%02X", key_config_low);
sprintf(key_config_high_str, "0x%02X", key_config_high);
cJSON_AddItemToArray(key_config_arr,
cJSON_CreateString(key_config_low_str));
cJSON_AddItemToArray(key_config_arr,
cJSON_CreateString(key_config_high_str));
cJSON_AddItemToObject(slot_obj, "key_config", key_config_arr);
// Add 16-bit binary representation
char key_config_bin[18];
for (int b = 0; b < 16; b++) {
key_config_bin[15 - b] = ((key_config >> b) & 1) ? '1' : '0';
}
key_config_bin[16] = '\0';
cJSON_AddStringToObject(slot_obj, "key_config_binary", key_config_bin);
cJSON_AddBoolToObject(slot_obj, "is_secret", (slot_config & 0x8000) != 0);
cJSON_AddBoolToObject(slot_obj, "encrypt_read",
(slot_config & 0x4000) != 0);
cJSON_AddBoolToObject(slot_obj, "is_private", (key_config & 0x0001) != 0);
cJSON_AddItemToArray(slots, slot_obj);
}
cJSON_AddItemToObject(root, "slots", slots);
// Additional fields
cJSON_AddNumberToObject(root, "user_extra", config[84]);
cJSON_AddNumberToObject(root, "selector", config[85]);
char *json_str = cJSON_Print(root);
cJSON_Delete(root);
return json_str;
}
/**
* Release ATECC608B resources
*/
void atecc608B_release() { atcab_release(); }
#endif // ATECC608B_H