Skip to content

Secure Element Phase 3: Production Lock Configuration #89

@kwsantiago

Description

@kwsantiago

Overview

Final ATECC608B configuration and permanent lock for production deployment.

Prerequisites

Production Slot Configuration

Slot Access Policy

// Slot 4: Master Key - encrypted read, no write after lock
// Slot 5: Device ID - clear read, no write after lock  
// Slot 6: PIN HMAC - no read, HMAC operations only
// Slot 7: Counter - increment only, no direct write

Zone Locking Sequence

int se_production_lock(void) {
    ATCA_STATUS status;
    
    // 1. Verify all slot data is correct
    if (!verify_slot_contents()) {
        ESP_LOGE(TAG, "Slot verification failed - aborting lock");
        return -1;
    }
    
    // 2. Lock data zone (slots become read-only per policy)
    status = atcab_lock_data_zone();
    if (status != ATCA_SUCCESS) return -2;
    
    // 3. Lock config zone (configuration becomes immutable)
    status = atcab_lock_config_zone();
    if (status != ATCA_SUCCESS) return -3;
    
    ESP_LOGI(TAG, "SE permanently locked for production");
    return 0;
}

Security Features to Enable

PIN Attempt Counter

// Monotonic counter for PIN attempts
// Cannot be reset - device bricks after limit
#define PIN_ATTEMPT_LIMIT 10

int se_check_pin_attempts(void) {
    uint32_t attempts;
    se_get_counter(&attempts);
    
    if (attempts >= PIN_ATTEMPT_LIMIT) {
        // Trigger secure wipe
        return SE_BRICKED;
    }
    return SE_OK;
}

Secure Boot Binding

// Bind SE operations to verified boot state
int se_verify_boot_state(void) {
    uint8_t boot_digest[32];
    esp_secure_boot_get_digest(boot_digest);
    
    // Compare against stored expected digest
    return se_verify_hmac(SE_SLOT_PIN_HMAC, boot_digest, 32);
}

Pre-Lock Checklist

  • Slot 4 contains valid master key material
  • Slot 5 contains unique device ID
  • Slot 6 configured for HMAC operations
  • Slot 7 counter initialized to 0
  • Access policies verified on unlocked device
  • Recovery procedure documented (there is none - new device required)

Production Build Integration

#ifdef CONFIG_PRODUCTION_BUILD
    // Verify SE is locked
    bool config_locked, data_locked;
    atcab_is_locked(LOCK_ZONE_CONFIG, &config_locked);
    atcab_is_locked(LOCK_ZONE_DATA, &data_locked);
    
    if (!config_locked || !data_locked) {
        ESP_LOGE(TAG, "SE not locked - refusing to run production build");
        abort();
    }
#endif

Acceptance Criteria

  • Lock sequence documented and tested on spare device
  • Production build refuses to run on unlocked SE
  • PIN counter enforced by SE hardware
  • No way to extract key material after lock
  • Secure boot binding operational
  • Factory provisioning procedure documented

Security Design Principles

FROST Shares Stay in Software

FROST secret shares are stored in encrypted flash, not in the SE:

  • Shares are too large for SE slots (72 bytes max per slot)
  • FROST threshold provides cryptographic protection - compromising one device yields nothing
  • SE protects the storage encryption key, not the shares directly

Key Generation On-Device

  • Never import private keys - generate all keys on the device using SE's internal RNG
  • Use atcab_genkey() for ECC keys, not atcab_write()
  • This ensures keys never exist outside the SE

SE RNG for Entropy Mixing

// Mix SE hardware RNG into system entropy pool
uint8_t se_random[32];
atcab_random(se_random);
esp_fill_random_add_entropy(se_random, 32);

Use SE's certified RNG to supplement ESP32 RNG for critical operations.

Warnings

⚠️ LOCK IS PERMANENT - No undo, no recovery
⚠️ Test lock sequence on spare hardware first
⚠️ Document exact configuration before locking
⚠️ Keep unlocked devices for development

Related

Metadata

Metadata

Assignees

Labels

hardp1PrioritysecuritySecurity-related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions