1. Тема дня

Сегодня разбираем механизмы безопасности:

text
Secure Boot        — разрешает запуск только доверенного firmware
Flash Encryption   — скрывает содержимое внешней Flash
TrustZone          — изолирует код и данные во время выполнения
Secure Storage     — защищает ключи и секретные параметры
Anti-rollback      — запрещает запуск отозванных старых версий

Главная мысль: Secure Boot защищает цепочку загрузки, TrustZone — границу доступа во время работы, а шифрование Flash — данные в выключенном устройстве. Ни один механизм не заменяет остальные.

2. Зачем это нужно в твоих проектах

В прошивках появляются чувствительные активы:

text
MQTT client private key
пароли APN и серверов
ключи подписи команд
ключи шифрования конфигурации
сертификаты устройства
параметры безопасного OTA
anti-replay counters
заводская калибровка
критичные GPIO и силовые выходы

Ошибка в AT-парсере может привести к выполнению кода, который прочитает MQTT private key. MPU помогает ловить память, но не создаёт полноценную cryptographic boundary. TrustZone на STM32U5/H5/Cortex-M33 может отделить ключи и secure services от обычного приложения. Для классического ESP32-WROOM-32U TrustZone нет; там основа — Secure Boot, Flash Encryption, NVS Encryption, eFuse, уникальные device keys и архитектурное ограничение доступа.

3. Теория

6.3.1 3.1. Модель угроз

Перед включением security-флагов нужно определить:

text
что защищаем;
от кого защищаем;
в каком состоянии устройства;
что допустимо потерять.

6.3.2 3.2. Secure Boot

Цепочка доверия:

text
ROM / immutable Root of Trust
→ проверка bootloader
→ проверка приложения
→ переход к выполнению

Secure Boot проверяет подлинность кода. Он не скрывает содержимое firmware.

6.3.3 3.3. Flash Encryption

Flash Encryption скрывает содержимое внешней Flash. Но без Secure Boot не гарантирует, что запускаемый код доверенный.

text
Secure Boot без Flash Encryption:
  код проверяется, но может читаться с Flash.
Flash Encryption без Secure Boot:
  код скрыт, но подлинность цепочки слабее.

6.3.4 3.4. TrustZone

На Cortex-M33 систему можно разделить:

text
Secure world:
  ключи;
  crypto;
  проверка OTA;
  secure storage;
  критичные счётчики;
  часть peripherals.
NonSecure world:
  FreeRTOS;
  EC25 parser;
  MQTT/TCP;
  UI;
  обычная логика.

Secure API должен быть узким:

c
typedef enum {
    SECURE_STATUS_OK = 0,
    SECURE_STATUS_INVALID_ARG,
    SECURE_STATUS_DENIED,
    SECURE_STATUS_INTERNAL_ERROR,
} secure_status_t;
secure_status_t secure_sign_event(const uint8_t *message,
                                  size_t message_size,
                                  uint8_t *signature,
                                  size_t signature_capacity,
                                  size_t *signature_size);

Private key никогда не возвращается наружу. 6.3.5 3.5. Secure Service проверяет аргументы

Secure-мир не доверяет NonSecure-вводу. Нужно проверять pointer, length, output capacity, состояние, role, rate limits, replay. Плохой API:

c
const uint8_t *secure_get_private_key(void);

Хороший:

c
secure_status_t secure_hmac_calculate(secure_key_id_t key_id,
                                      const void *message,
                                      size_t message_size,
                                      void *output,
                                      size_t output_size);

6.3.6 3.6. Что помещать в Secure-мир

Стоит помещать:

text
проверку подписи OTA
device identity key
HMAC/signing service
anti-replay counter
security version
factory provisioning state
secure storage
критичную операцию подтверждения firmware

Не стоит помещать:

text
весь MQTT client
JSON parser
AT-парсер EC25
весь FreeRTOS application
logger
веб-сервер
сложную бизнес-логику

6.3.7 3.7. Anti-rollback

Разделяй:

text
firmware version:
  меняется каждый релиз
build number:
  монотонно растёт
security version:
  меняется только при отзыве старой security generation

Не увеличивай secure_version на каждом обычном релизе, иначе потеряешь функциональный rollback.

6.3.8 3.8. Provisioning

text
DEVELOPMENT
→ тестовые ключи, debug открыт
PILOT
→ production-like ключи, тест recovery
PRODUCTION
→ финальные ключи, eFuse/option bytes, provisioning report

Private signing key не должен храниться в Git, Docker image, HIL Raspberry Pi или PR-job CI.

4. Типичные ошибки

text
1. Считать Flash Encryption заменой Secure Boot.
2. Считать Secure Boot защитой секретов в RAM.
3. Поместить весь проект в Secure-мир.
4. Передать NonSecure-коду pointer на ключ.
5. Не проверять NonSecure pointer и length.
6. Хранить signing key в обычном CI secret.
7. Включить eFuse/option bytes на единственной отладочной плате.
8. Использовать один symmetric key на весь парк.
9. Помещать private key в логи или core dump.
10. Не проектировать ротацию ключей.

5. Практическое задание на 30-60 минут

Создай SECURITY_ARCHITECTURE.md:

markdown
# Security architecture
## Assets
| Asset | Confidential? | Integrity critical? | Location |
|---|---:|---:|---|
| Firmware signing private key | yes | yes | offline signing environment |
| Firmware verification key | no | yes | eFuse/bootloader |
| MQTT device private key | yes | yes | secure storage/encrypted NVS |
| CA certificate | no | yes | firmware/read-only storage |
| APN password | yes | medium | encrypted NVS |
| Phase policy | no | yes | signed config/read-only runtime |
| Boot counter | no | yes | protected persistent storage |

Для ESP32 нарисуй:

text
Untrusted/external:
  EC25 bytes, MQTT, HTTP, CLI
Application:
  parser, networking, phase logic
Security services:
  OTA verification, encrypted storage
Hardware root:
  eFuse, Secure Boot digest, flash encryption key

Для STM32 TrustZone:

text
NonSecure:
  EC25, MQTT, Modbus, UI, phase logic
Secure:
  key operations, OTA verification,
  anti-replay counter, secure storage
Immutable Root:
  STiRoT/OEMiRoT

6. Что почитать дальше

  • ESP-IDF Security Overview, Secure Boot v2, Flash Encryption.
  • STM32H5/U5 TrustZone, STiRoT/OEMiRoT, OBKeys, secure storage.

Короткий итог

text
immutable root
→ verified bootloader
→ verified application
→ Secure/NonSecure boundary
→ narrow secure services
→ isolated device keys
→ signed OTA
→ anti-rollback
→ controlled provisioning

Задание

Application просит secure service подписать arbitrary input и вернуть pointer на private key. Перепроектируйте interface и validation boundary.

Критерии самопроверки: Объяснить проверку untrusted pointer и output capacity; одно название TrustZone не проверяет опасный API.

Показать ответ автора

Никогда не возвращать private key или pointer на него. Предоставить узкую operation, например signing bounded digest, проверять input/output ranges и lengths, authorization/state/rate limits и сохранять key operations внутри secure boundary.

Задание

Разделите firmware version, build number и security version в release policy, сохраняющей functional rollback и отзывающей compromised generation.

Критерии самопроверки: Описать revocation decision и recovery/provisioning evidence до изменения irreversible device settings.

Показать ответ автора

Firmware version определяет feature release; build number растёт монотонно; security version меняется при отзыве older security generation. Не повышать irreversible security threshold для каждого обычного feature release.