레이블이 Security-SecureBoot인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Security-SecureBoot인 게시물을 표시합니다. 모든 게시물 표시

10/21/2022

ESP32 Secure Boot 와 OTP

1. ESP32 Secure Boot 기본개념

  • ARM/ESP32 Secure Boot 관련비교 내용 
ARM의 Secure Boot 와 ESP32의 Secure Boot의 기본개념을 설명 
반드시 이해를 해야하며, 이를 이해해야 아래의 내용도 이해가능 

  • ESP32의 Startup Boot Flow
  1. 1st stage bootloader : ESP32 내부에 존재하는 Bootloader로 ROM에 이미 저장
  2. 2nd stage bootloader: ESP32의 SPI Flash 저장되어진 실제적인 bootloader image 이며 Partition table 접근가능
  3. application image: app image로 factory or ota 영역에 저장되는 application image

상위와 같이 ESP32는 Booting하며, User가 신경써야 할 부분은 2nd StageApplication image이다. 


1.1 ESP32 Secure Boot Version  

Espressif에서는 Secure Boot V1, V2을 제공하고 있지만, V2 더 권장하고 있으며, 다음과 같은 차이가 존재한다. 

  1. SecureBoot v1 : ESP32 Silicon Version1/2에서 지원가능
  2. SecureBoot v2 : ESP32 Silicon Version3에서 지원가능

  • ESP32 Secure Boot v1 for ESP32 Revision1/2
  1. AES-256-ECB 방식으로 bootloader Encoding/Decoding  
  2. ECSDA Signature 기반으로 appImage Signing/Verification  Image검증  
  3. OTP(eFUSE) 의 Block 2에  AES 256 bit 저장이용 
  4. OTP(eFUSE) 의 ABS_DONE_0 설정 

  • ESP32 Secure Boot v2 for ESP32 Revision3
  1. RSA3072 Key 기반으로 Signature 기반 bootloader Signing/Verification  Image검증  
  2. RSA3072 Key 기반으로 Signature 기반 appImage Signing/Verification  Image검증     
  3. OTP(eFUSE) 의 Block 2에 SHA-256 bit digest 이용하여 RSA3072 Public Key 검증 
  4. OTP(eFUSE) 의 ABS_DONE_1 설정 


1.2  Secureboot 의 Signing 과 Verfication 이해 

Secure Boot의 기본개념인 Signing 과 Verfication을 알아보도록 하자 
흔히, 비대칭키를 이용하여 Sign을 하여, Signature 생성하고, 이를 검증(Verfication)하는 것이다.

Android System의 Sign 과 Vefication 이해 

암호화 기본개념(비대칭키 와 대칭키 이외 기본개념) 

ECDSA 기반의 Key 와 Certificate 세부분석



  • Secure Boot Signing
  1. 비대칭키 기반 사용 (RSA,ECDSA)
  2. Build를 한 후 image를 생성할때 Private Key로 Signature를 생성

  • Secure Boot Verification 
  1. 비대칭키 기반 사용 (RSA,ECDSA)
  2. 이미 생성된 Signature를 Public Key를 이용하여 이를 검증 

2. ESP32 Secure Boot 설정 과 진행 


우선 Signature를 만들기 위해서, 즉 Signing을 위한 Key가 필요하다. 


2.1 RSA Signing Key 생성방법 


Window용 ESP-IDF가 버그가 있어 아래와 같이 export.bat 수정하도록 한다.  
아래는 Powershell 용이 아니라 Command 용이므로 참고하도록하자. 

  • ESP-IDF 버그 수정 (v.4.2.3)
수정후 espsecure.py 사용가능
cd  %userprofile%\esp\esp-idf\export.bat  //수정 export.bat (Window에서 espsecure.py 미지원)

....
DOSKEY idf.py=python.exe "%IDF_PATH%\tools\idf.py" $*
DOSKEY esptool.py=python.exe "%IDF_PATH%\components\esptool_py\esptool\esptool.py" $*
DOSKEY espefuse.py=python.exe "%IDF_PATH%\components\esptool_py\esptool\espefuse.py" $*
DOSKEY espsecure.py=python.exe "%IDF_PATH%\components\esptool_py\esptool\espsecure.py" $*
DOSKEY otatool.py=python.exe "%IDF_PATH%\components\app_update\otatool.py" $*
DOSKEY parttool.py=python.exe "%IDF_PATH%\components\partition_table\parttool.py" $*

echo Checking if Python packages are up to date...
python.exe "%IDF_PATH%\tools\check_python_dependencies.py"
if %errorlevel% neq 0 goto :end

echo.
echo Done! You can now compile ESP-IDF projects.
echo Go to the project directory and run:
echo.
echo   idf.py build
echo.
....


RSA Signing Key를 꼭 espsecure.py로 생성할 필요는 없으며, openssl로 쉽게 생성가능.

  • RSA3072 Key 생성방법-A 
openssl을 이용하여  Singing Key 생성 방법 
$ openssl genrsa -out my_secure_boot_signing_key.pem 3072
$ cp ./my_secure_boot_signing_key.pem /mnt/d/Works/   

  • RSA3072 Key 생성방법-B
espsecure.py 이용하여 쉽게 생성가능하며, 각 Version 별로 설정가능  
$ espsecure.py generate_signing_key -v2 test1.pem   
$ espsecure.py generate_signing_key -v1 test1.pem   
$ espsecure.py sign_data --version 2 --keyfile my_secure_boot_signing_key.pem  --output ./build/app_sign.bin ./build/app.bin 

  • ESP SecureBoot Version1
ESP32의 경우, Revision3 부터 사용권장
PEM 방식으로 ECDSA Signing/Verification 동작 

ESP32 SecureBootV1 Manual 

  • ESP SecureBoot Version2 
이를 좀 더 권장하며, ESP32 ECO3 이상에서 사용가능하며, RSA-PSS 방식이라고 말한다.
PEM 의 RSA3072 기반으로 Signing/Verfication 방식
OTP(eFUSE, One Time Programming)  Block2 의 Secure Boot에 RSA Public Key의 Hash를 넣는 구조


  • ESP32 와 외부 Security Chip 사용 
ESP32에서 ECDSA의 Sign/Verify를 사용하기 위해서 외부 Chip를 사용 
이전에 설명한 CMVP/KCMVP 기능이라고 생각하면 될 것 같으며, 확장기능으로 이를 이용하여 TLS도 가능하다 


2.2 OTP(eFuse) 구조 와 역할 

ESP32 의 경우, 1024bit 의 OTP(One Time Programmable, eFUSE)를 가지고 있고, 각 Block은 256bit로 총 4개로 나누어 분리하여 사용하도록 한다. 
주의 해야할 것은 OTP(One Time Programmable) 한 번만 Write가 가능하므로, 신중하게 하도록하자. 
실패하면, 쓸모가 없어진다. 

  • OTP(eFUSE) 구조 

  • OTP(One Time Programable,eFuse) Manual 
ESP-IDF Version에 따라 조금씩 다르므로 각 버전에 맞게 참조하도록 하자 

  • ESP32 burn-efuse 설명 


  • ESP32 OTP 사용방법 
설정하는 방법은 현재 Command 중심으로 하는게 제일 편하며, ESP-IDF 개발환경에서 VS Code용 EFUSE Exploerer를 별도로 제공을 해주고 있다. 
  1. UI 중심: VS Code EFUSE Exploerer
  2. Command 중심 아래 참조 


2.3 OTP(eFuse) Command 기반 사용법 

실제로 ESP32에서 제공하는 eFuse, OTP 설정값들을 확인해보고, 제어를 해보도록하자. 

  • Window에서 ESP-IDF 활성화   
ESP-IDF가 현재 venv기반의 Python으로 되어있으므로 이를 활성화 부터 해야한다.

Command로 할 경우, 
%userprofile%\.espressif\python_env\idf4.2_py3.8_env\Scripts\activate.bat
%userprofile%\esp\esp-idf\export.bat

PowerShell 할 경우,
$Env:userprofile\.espressif\python_env\idf4.2_py3.8_env\Scripts\activate.ps1
$Env:userprofile\esp\esp-idf\export.ps1

Window 용 PowerShell 관련내용 
주의, Powershell의 경우 Version 따라 동작이 많이 다르며, 점차 Linux 처럼 변경 중 


  • idf.py show_efuse_table (각 OTP 내부구성파악)
OTP인 eFuse에 각 Table 구성과 Field name을 쉽게 파악가능하다. 

(idf4.2_py3.8_env) D:\Works\Project\>idf.py show_efuse_table  //ESP Project 내에서 실행하며, 각 Field name 파악
Executing action: show_efuse_table
Running ninja in directory d:\works\project\mod610_sw\build
Executing "ninja show_efuse_table"...
[1/1] cmd.exe /C "cd /D D:\Works\Project\mod610_sw\build\esp-idf\efus...ts/efuse/esp32/esp_efuse_table.csv -t esp32 --max_blk_len 192 --info" 
Parsing efuse CSV input file C:/Users/jhlee/esp/esp-idf/components/efuse/esp32/esp_efuse_table.csv ...
Verifying efuse table...
Max number of bits in BLK 192
Sorted efuse table:
#       field_name                      efuse_block     bit_start       bit_count  //Field name 과 Block 위치 와 Bit Start 파악
1       WR_DIS_FLASH_CRYPT_CNT          EFUSE_BLK0         2               1
2       WR_DIS_BLK1                     EFUSE_BLK0         7               1
3       WR_DIS_BLK2                     EFUSE_BLK0         8               1
4       WR_DIS_BLK3                     EFUSE_BLK0         9               1
5       RD_DIS_BLK1                     EFUSE_BLK0         16              1
6       RD_DIS_BLK2                     EFUSE_BLK0         17              1
7       RD_DIS_BLK3                     EFUSE_BLK0         18              1
8       FLASH_CRYPT_CNT                 EFUSE_BLK0         20              7
9       UART_DOWNLOAD_DIS               EFUSE_BLK0         27              1
10      MAC_FACTORY                     EFUSE_BLK0         32              8
11      MAC_FACTORY                     EFUSE_BLK0         40              8
12      MAC_FACTORY                     EFUSE_BLK0         48              8
13      MAC_FACTORY                     EFUSE_BLK0         56              8
14      MAC_FACTORY                     EFUSE_BLK0         64              8
15      MAC_FACTORY                     EFUSE_BLK0         72              8
16      MAC_FACTORY_CRC                 EFUSE_BLK0         80              8
17      CHIP_VER_DIS_APP_CPU            EFUSE_BLK0         96              1
18      CHIP_VER_DIS_BT                 EFUSE_BLK0         97              1
19      CHIP_VER_PKG                    EFUSE_BLK0        105              3
20      CHIP_CPU_FREQ_LOW               EFUSE_BLK0        108              1
21      CHIP_CPU_FREQ_RATED             EFUSE_BLK0        109              1
22      CHIP_VER_REV1                   EFUSE_BLK0        111              1
23      ADC_VREF_AND_SDIO_DREF          EFUSE_BLK0        136              6
24      XPD_SDIO_REG                    EFUSE_BLK0        142              1
25      SDIO_TIEH                       EFUSE_BLK0        143              1
26      SDIO_FORCE                      EFUSE_BLK0        144              1
27      CHIP_VER_REV2                   EFUSE_BLK0        180              1
28      ENCRYPT_CONFIG                  EFUSE_BLK0        188              4
29      CONSOLE_DEBUG_DISABLE           EFUSE_BLK0        194              1
30      ABS_DONE_0                      EFUSE_BLK0        196              1
31      DISABLE_JTAG                    EFUSE_BLK0        198              1
32      DISABLE_DL_ENCRYPT              EFUSE_BLK0        199              1
33      DISABLE_DL_DECRYPT              EFUSE_BLK0        200              1
34      DISABLE_DL_CACHE                EFUSE_BLK0        201              1
35      ENCRYPT_FLASH_KEY               EFUSE_BLK1         0              192
36      SECURE_BOOT_KEY                 EFUSE_BLK2         0              192
37      MAC_CUSTOM_CRC                  EFUSE_BLK3         0               8
38      MAC_CUSTOM                      EFUSE_BLK3         8               48
39      ADC1_TP_LOW                     EFUSE_BLK3         96              7
40      ADC1_TP_HIGH                    EFUSE_BLK3        103              9
41      ADC2_TP_LOW                     EFUSE_BLK3        112              7
42      ADC2_TP_HIGH                    EFUSE_BLK3        119              9
43      SECURE_VERSION                  EFUSE_BLK3        128              32
44      MAC_CUSTOM_VER                  EFUSE_BLK3        184              8

Used bits in efuse table:
EFUSE_BLK0
[2 2] [7 9] [16 18] [20 27] [32 87] [96 97] [105 109] [111 111] [136 144] [180 180] [188 191] [194 194] [196 196] [198 201]

EFUSE_BLK1
[0 191]

EFUSE_BLK2
[0 191]

EFUSE_BLK3
[0 55] [96 159] [184 191]

Note: Not printed ranges are free for using. (bits in EFUSE_BLK0 are reserved for Espressif)



  • espefuse.py 사용법 (OTP 제어방법 확인)
아래와 같이 기본사용법을 확인을 반드시 하도록하며, 각 명령어에 따라 사용하도록하자. 
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py  //esefuse 사용법확인 
espefuse.py v3.1-dev
usage: espefuse.py [-h] [--chip {auto,esp32,esp32s2,esp32s3beta2,esp32s3beta3,esp32c3}] [--baud BAUD] [--port PORT]
                   [--before {default_reset,no_reset,esp32r1,no_reset_no_sync}] [--debug] [--virt] [--path-efuse-file PATH_EFUSE_FILE]        
                   [--do-not-confirm]
                   {burn_efuse,read_protect_efuse,write_protect_efuse,burn_block_data,burn_bit,adc_info,dump,summary,burn_key,burn_key_digest,set_flash_voltage,burn_custom_mac,get_custom_mac}
                   ...

positional arguments:
  {burn_efuse,read_protect_efuse,write_protect_efuse,burn_block_data,burn_bit,adc_info,dump,summary,burn_key,burn_key_digest,set_flash_voltage,burn_custom_mac,get_custom_mac}
                        Run espefuse.py {command} -h for additional help
    burn_efuse          Burn the efuse with the specified name   //Feild name 기반 Write 기능,  burn_bit 와 동일 
    read_protect_efuse  Disable readback for the efuse with the specified name
    write_protect_efuse
                        Disable writing to the efuse with the specified name
    burn_block_data     Burn non-key data to EFUSE blocks. (Don't use this command to burn key data for Flash Encryption or ESP32 Secure      
                        Boot V1, as the byte order of keys is swapped (use burn_key)).
    burn_bit            Burn bit in the efuse block.   //burn_efuse 거의 동일하며, Block 과 Bit를 입력하여 Write  
    adc_info            Display information about ADC calibration data stored in efuse.
    dump                Dump raw hex values of all efuses
    summary             Print human-readable summary of efuse values
    burn_key            Burn a 256-bit key to EFUSE: BLOCK1, flash_encryption, BLOCK2, secure_boot_v1, secure_boot_v2, BLOCK3
    burn_key_digest     Parse a RSA public key and burn the digest to eFuse for use with Secure Boot V2
    set_flash_voltage   Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. This means GPIO12 can be high or    
                        low at reset without changing the flash voltage.
    burn_custom_mac     Burn a 48-bit Custom MAC Address to EFUSE BLOCK3.
    get_custom_mac      Prints the Custom MAC Address.

optional arguments:
  -h, --help            show this help message and exit
  --chip {auto,esp32,esp32s2,esp32s3beta2,esp32s3beta3,esp32c3}, -c {auto,esp32,esp32s2,esp32s3beta2,esp32s3beta3,esp32c3}
                        Target chip type
  --baud BAUD, -b BAUD  Serial port baud rate used when flashing/reading
  --port PORT, -p PORT  Serial port device
  --before {default_reset,no_reset,esp32r1,no_reset_no_sync}
                        What to do before connecting to the chip
  --debug, -d           Show debugging information (loglevel=DEBUG)
  --virt                For host tests, the tool will work in the virtual mode (without connecting to a chip).
  --path-efuse-file PATH_EFUSE_FILE
                        For host tests, saves efuse memory to file.
  --do-not-confirm      Do not pause for confirmation before permanently writing efuses. Use with caution.



  • espefuse.py 사용방법 (OTP 설정값 확인용)
실제 Serial에 연결하여 각 설정 값을 확인하도록 하자 
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 summary     //OTP 설정된것 확인용 
Connecting....
Detecting chip type... ESP32
espefuse.py v3.1-dev
EFUSE_NAME (Block)                       Description  = [Meaningful Value] [Readable/Writeable] (Hex Value)
----------------------------------------------------------------------------------------
Calibration fuses:
BLK3_PART_RESERVE (BLOCK0):              BLOCK3 partially served for ADC calibration data   = False R/W (0b0)
ADC_VREF (BLOCK0):                       Voltage reference calibration                      = 1114 R/W (0b00010)

Config fuses:
XPD_SDIO_FORCE (BLOCK0):                 Ignore MTDI pin (GPIO12) for VDD_SDIO on reset     = False R/W (0b0)
XPD_SDIO_REG (BLOCK0):                   If XPD_SDIO_FORCE, enable VDD_SDIO reg on reset    = False R/W (0b0)
XPD_SDIO_TIEH (BLOCK0):                  If XPD_SDIO_FORCE & XPD_SDIO_REG                   = 1.8V R/W (0b0)
CLK8M_FREQ (BLOCK0):                     8MHz clock freq override                           = 55 R/W (0x37)
SPI_PAD_CONFIG_CLK (BLOCK0):             Override SD_CLK pad (GPIO6/SPICLK)                 = 0 R/W (0b00000)
SPI_PAD_CONFIG_Q (BLOCK0):               Override SD_DATA_0 pad (GPIO7/SPIQ)                = 0 R/W (0b00000)
SPI_PAD_CONFIG_D (BLOCK0):               Override SD_DATA_1 pad (GPIO8/SPID)                = 0 R/W (0b00000)
SPI_PAD_CONFIG_HD (BLOCK0):              Override SD_DATA_2 pad (GPIO9/SPIHD)               = 0 R/W (0b00000)
SPI_PAD_CONFIG_CS0 (BLOCK0):             Override SD_CMD pad (GPIO11/SPICS0)                = 0 R/W (0b00000)
DISABLE_SDIO_HOST (BLOCK0):              Disable SDIO host                                  = False R/W (0b0)

Efuse fuses:
WR_DIS (BLOCK0):                         Efuse write disable mask                           = 0 R/W (0x0000)
RD_DIS (BLOCK0):                         Efuse read disable mask                            = 0 R/W (0x0)
CODING_SCHEME (BLOCK0):                  Efuse variable block length scheme
   = NONE (BLK1-3 len=256 bits) R/W (0b00)
KEY_STATUS (BLOCK0):                     Usage of efuse block 3 (reserved)                  = False R/W (0b0)

Identity fuses:
MAC (BLOCK0):                            Factory MAC Address
   = c4:dd:57:71:08:08 (CRC 0x5f OK) R/W
MAC_CRC (BLOCK0):                        CRC8 for factory MAC address                       = 95 R/W (0x5f)
CHIP_VER_REV1 (BLOCK0):                  Silicon Revision 1                                 = True R/W (0b1)
CHIP_VER_REV2 (BLOCK0):                  Silicon Revision 2                                 = True R/W (0b1)
CHIP_VERSION (BLOCK0):                   Reserved for future chip versions                  = 2 R/W (0b10)
CHIP_PACKAGE (BLOCK0):                   Chip package identifier                            = 1 R/W (0b001)
MAC_VERSION (BLOCK3):                    Version of the MAC field                           = 0 R/W (0x00)

Security fuses:
FLASH_CRYPT_CNT (BLOCK0):                Flash encryption mode counter                      = 0 R/W (0b0000000)
UART_DOWNLOAD_DIS (BLOCK0):              Disable UART download mode (ESP32 rev3 only)       = False R/W (0b0)
FLASH_CRYPT_CONFIG (BLOCK0):             Flash encryption config (key tweak bits)           = 0 R/W (0x0)
CONSOLE_DEBUG_DISABLE (BLOCK0):          Disable ROM BASIC interpreter fallback             = True R/W (0b1)
ABS_DONE_0 (BLOCK0):                     Secure boot V1 is enabled for bootloader image     = False R/W (0b0)
ABS_DONE_1 (BLOCK0):                     Secure boot V2 is enabled for bootloader image     = False R/W (0b0)
JTAG_DISABLE (BLOCK0):                   Disable JTAG                                       = False R/W (0b0)
DISABLE_DL_ENCRYPT (BLOCK0):             Disable flash encryption in UART bootloader        = False R/W (0b0)
DISABLE_DL_DECRYPT (BLOCK0):             Disable flash decryption in UART bootloader        = False R/W (0b0)
DISABLE_DL_CACHE (BLOCK0):               Disable flash cache in UART bootloader             = False R/W (0b0)
BLOCK1 (BLOCK1):                         Flash encryption key
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK2 (BLOCK2):                         Secure boot key
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
BLOCK3 (BLOCK3):                         Variable Block 3
   = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W

Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V).
상위보다는 거의 사용하지 않겠지만, 다른 기계와 설정값 비교할때는 dump가 최고 
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 dump //OTP 설정된것 확인용 
Connecting....
Detecting chip type... ESP32
BLOCK0          (                ) [0 ] read_regs: 00000000 57710808 005fc4dd 0000a200 00000237 00100000 00000004
BLOCK1          (flash_encryption) [1 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK2          (secure_boot_v1 s) [2 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK3          (                ) [3 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
espefuse.py v3.1-dev
만약, MAC을 사서 사용한다면 그때 설정하고 확인 
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 get_custom_mac  //기본으로 사용하므로 없음
Connecting.....
Detecting chip type... ESP32
espefuse.py v3.1-dev
Custom MAC Address is not set in the device.

  • Secure Boot 설정완료 후 OTP 설정 할 것 
SecureBoot를 완벽히 진행하려면, 나중에는 JTAG 과 UART를 막아야 하며, 이후 부터 OTA로만 진행 
  1. ESP32 의 JTAG 막기 
  2. ESP32 UART BOOT 막기 
//EfuseDefineFields
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_efuse   JTAG_DISABLE 1        --before default_reset --do-not-confirm   
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_efuse   UART_DOWNLOAD_DIS 1   --before default_reset --do-not-confirm   //주의: 이후 Serial로 eFUSE도 동작안됨
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_efuse   CONSOLE_DEBUG_DISABLE 1

(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_bit BLOCK0 198   //DISABLE_JTAG  , 상위와 동일 
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_bit BLOCK0 27    //UART_DOWNLOAD_DIS
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 burn_bit BLOCK0 194   //CONSOLE_DEBUG_DISABLE

--before default_reset --do-not-confirm  반드시 사용 


(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 adc_info

(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 read_protect_efuse  BLOCK0
(idf4.2_py3.8_env) D:\Works\Project> espefuse.py -p COM15 write_protect_efuse



eFUSE API를 사용할 경우 



10/13/2022

Secure Boot (ESP32/ARM) 비교 및 기본이해

1. 기본 Certificate 활용 및 암호화 이해 

일반 기본 암호화 개념부터 알고, 그 다음에 Cetificate 를 왜 사용하는지 부터 알아보도록하자.
정확히 Authentication(인증)이라고 하는게 맞을 것 같다. 

주로 많이 사용되는 것은 TLS/SSL일 것이며, 이를 이용한 HTTPS 비롯하여 다양한 네트워크 프로토콜에서 사용되어지고 있다. 
그리고, 이를 넘어 Security Boot 를 비롯하여, Android app 인증등 많은 곳에서 사용되어지는 암호화 기술이다. 


  • 각 기본용어확인 
Authentication 과 Public Key 기반의 Certificate 및 Format X.509

보통 Certificate는 X.509 Format로 저장되어지므로 상위 기본내용은 알아두도록 하자. 

  • 암호화 기본개념
암호화의 기본개념과 Cetificate 기반의 TLS 기본이해 

  • Android의 인증시스템 구조 
Android에서 App을 인증하는 방법으로 Cerficate 기반의 Singining 과 Verfication  

  • SELinux(Security-Enhanced Linux)
SELinux로  Linux에서 인증된 App 과 그렇지 못한 App을 구분하여 실행하는 구조이다. (상위 Android 와 비슷하다.)  
OP-TEE기능으로 구현이 되어있을 지도 모르며, Selinux 기능은 Kernel Argument로 on/off를 할 수 있는 것으로 기억하며 Kernel config도 있다. 

  • ECDSA  Key 및 Certificate 생성 및 분석 
요즘 대세인 ECSDA Cerficiate 구조 구성 및 세부분석 과 사용방법 

  • WIFI-WPA 인증(Authentication)
WIFI의 EAP methods에서도 사용되어지며, 이부분은 Layer 2부터 같이 동작되어지며, WIFI기본 동작으로 알고 있어야 한다. 



1.1 PKCS11 와 HW Module  

내가 PKCS11를 처음 접한 것은 KCMVP를 다루면서 관련 인증서들을 분석하며 알게되면서 부터일 것 같다.
 
일단 PKCS11는 HSMs/TPM/KCMVP/CMVP/SmartCard/uSIM 등에서 주로 HW 와 함께 사용되는 기술이라고 생각되면 될 꺼 같다. 

쉬운 예를들면, 특정 HW모듈에 PKCS11 Interface기반으로 인증서를 넣어 못 건들게 하고 이 기반으로 Secure Boot 부터 Network의 TLS 방식으로 암호화를 하는 것이다. 
대표적으로 쉽게 이해가능한게 TPM일 것 같다. 요즘 대부분 컴퓨터에 설치되어있으니까. 
물론, 각 기능은 사용자에 따라 사용되어지는 것이 다를 것이다.

이외에도 CMVP라고 HW모듈기반으로 TLS/DTLS 통신하는 것이 있으며, 다양한 것이 있으므로 너무 암호화를 한정적으로만  생각할 수가 없을 것 같다

이 내용을 Secure Boot에 다루는 이유는 이 HW기반으로 Booting에도 같이 사용되어지기 때문이며, 이외 다양하게 사용되어진다. 

  • PKCS(Public-Key Cryptography Standard) 11 관련내용
PKCS11의 경우 Token or Key를 저장하는 구조이며, 이에 관련 된 정보들은 아래 
  

2. ARM HW 암호화 구성   

ARM의 경우, TrunstZone과 다양한 HW 암호화를  제공하고 있어, ARM을 기반으로 보안기능을 제공하고 있으며, 
이 기능기반으로 Secure Boot로 뿐만 아니라 다양한 암호화 기능을 사용가능하다. 
암호화된 App 실행를 비롯하여, TLS/SSL 를 비롯하여 다양하게 사용되어진다.  

암호화에 대해서 너무 한정적으로 생각하지 말도록하자. 


2.1 ARM의 TrustZone 과 TEE 기능이해 

ARM의 경우는 TEE(Trust Execution Environment)REE(Rich Execution Environment)로 ARM 내부에서 분리되어 실행되어진다. 
이는 기본으로 MMU를 기반으로 Protection을 진행하여 제어하는 방법이 필수 일 것 같다. 

  1. TEE(Trust Execution Environment) : ARM의 TrustZone을 이용하여 실행되는 환경구조 
  2. REE(Rich Execution Environment): ARM의 TrustZone을 사용안하는 환경구조 


  • ARM의 TrustZone 과 MMU 사용  
다중 Core를 사용하다보니, MMU기반으로 분리를 하는게 쉽지는 않는 것으로 보인다. 


  • ARM에서 PKCS11 기반으로 OP-TEE 사용
NXP의 i.MX8의 Secure Boot 

  • OP-TEE를 이용하여 Secure Application 실행 
TA(Truested Application)

PKCS#11 과 OP-TEE의 i.MX8 관련내용(PCKS#11 TA)

PKCS#11 과 OP-TEE 의 IoT 관련내용 

OP-TEE 사용법과 이해  


  • ARM TrustZone
ARM에서 제공하는 HW적은 암호화 기능이며, 이를 확장하여 사용하는 것 TEE/REE    

  • Uboot의 TEE(Trusted Execution Environment) 
TEE(Trusted Execution Environment) 이며, 즉 Secure Boot를 비롯하여 Secure App, 다양한 암호화를 ARM HW부터 제공한다. 
Linux Command인 TEE 명령어와 혼동하지 말도록하자 

  • Uboot의 TEE(Trusted Execution Environment) 와 OP-TEE(Open Portable TEE) 예제 
Uboot에서 TEE를 설정하여 Secure Boot를 진행가능하며, OP-TEE도 설정가능 

  • Yocto에서는 OP-TEE(Open Portable TEE) 제공
이를 이용하여 Secure Boot를 비롯하여 인증된 App을 실행가능 한걸로 기억하며, 유사기술이 SELinux인걸로 기억한다. 

기존에 알고있는것을 다 정리 할 수 없을 것 같아 상위 정도로만, ARM 관련사항 정리를 마무리하고, 
TI Sitara or DM Series 확인을 한번 더 확인 



3. ESP32 HW 암호화


ESP32의 경우는 HW 암호화 기능과 OTP(One-Time Programmable), 즉 eFUSE를 제공하며, 다양한 암호화 기능을 제공한다.  
여기서 OTP(One-Time Programmable)이며, OTP(One-Time Password)이 가 아니므로 혼동하지 말자. 

결론적으로, ESP32도  eFUSE(One Time Programing) 이곳에서는 Secure Boot  PKCS11 기반의 Secure Boot와 거의 유사하게 동작가능한걸로 보인다.
(개인적으로는 ESP32에서 SRAM부분에서 부터 놀랬지만, 여기도 ESP32의 Secure boot에서도 나에게는 너무 좀 충격이였다)
ARM처럼 HW 암호화기능 있어, 거의 유사하게 동작가능하며, 이외 ESP32 HW 암호화 기능도 제공해주고 있다. 

ESP32를 가격이 싸다고 만만히 볼만한 MPU는 아닌것 같으며, 정말로 다양한 기능을 제공하고 있다


3.1 ESP32의 Secure Boot 

ESP32의 Secure Boot의 OTP(One Time Programing,eFUSE)기반으로 진행되는 Siging/Verfication 기술이며, 이를 ESP32에서 제공을 해준다. 
ESP32의 경우도 역시 내부적으로 HW적으로 암호화 기능을 제공해지만, ARM의 TrustZone 동작방식과는 다르며,
내부적으로 간단하게 구성하여 제공해주고 있다. 
간단히만 동작만 소개하고 다음에 세부적으로 다루겠다. 



  • OTP(One Time Programing,eFUSE)
ESP32 내부에 제공해주는 1024bit 저장장소 제공해주고 있으며, 각 256bit 씩 4개의 Block으로 관리되어 지고 있다. 
OTP(eFUSE)의 경우 0 -> 1로만 변경가능하며, 한번 1로 변경되면 변경 불가능하다. 
https://blog.espressif.com/understanding-esp32s-security-features-14483e465724


  • ESP32 의 Secure Boot 의 전체 Flow  
Reset 후 ROM에서 1st stage 인 ROM에서 Boot를 하고 OTP(eFUSE)의 설정에 따라 동작이 되어진다. 
  1. OTP(eFUSE)에 저장된 Key 값 기반으로 Flash의 BootLoader를 Load 하기 전에 Verify하고 Booting  
  2. Flash의 Bootloader는 Bootloader 처럼 App image를 Verify를 진행하여 Booting 

https://blog.espressif.com/understanding-esp32s-security-features-14483e465724

상위구조를 쉽게 설명하면, OTP(One Time Programiming, eFUSE)에는 저장소의 한계 (256bit) 때문에 Hash(Token) 이용하여 한 번 더 검증하는 방식이다. 
보통 다른 곳에서는 이 Hash를 Token이라고도 많이 부르기도 한다. 


  • SecureBoot 의 BootLoader 구성 과 OTP(eFuse) 
  1. Bootloader Image:  Flash 에서 실행가능한 일반적인 image 이며, 일반부팅은 이것만 필요 
  2. RSA Signature:  Certificate의 Signature 처럼 상위 Image의 RSA3072기반으로 Private Key 로 생성 
  3. RSA 3072 Public Key: 상위 RSA Signature를 확인하기 위해서 Public Key가 필요 
  4. OTP(eFUSE): 저장된 Key의 Hash(SHA-256)로 RSA 3072 Public Key가 Verify 검증 


  • Bootloader 를 실행하기 전에 아래의 동작을 수행 
  1. OTP(eFuse)의 Hash를 이용하여 RSA 3072 Public Key가 맞는지 확인(Public Key Verfication)
  2. RSA 3072 Public Key를 이용하여 RSA Signature를 확인가능  
  3. Bootloader 실행 (RSA Signature는 이미 검증된 것임)

https://blog.espressif.com/understanding-esp32s-security-features-14483e465724

일반 PKCS11 기반하고 할 경우에는 Certificate 와 Key 기반으로 이를 하지만, 상위처럼 Memory 한계 때문에, 한번 더 대칭키(Hash)를 추가하여 사용한다.


  • Flash 의 App Image의 기본구성 
상위와 동일한 구조 구조 이므로 생략 

  • Flash Encryption 
Secure Boot 기능을 넘어  Flash 저장된 정보를 ESP32 HW적으로 AES Key기반으로 Decrytion을 하여 동작가능하게 하는 기능이다. 
하지만, 이 기능을 사용하면, ESP32 성능과 Flash 기반의 XiP가 어떻게 될지가 좀 의문이다. 
그림상으로는 완벽하지만, 항상 실행해보면 문제가 생기는 경험을 많이 했기때문에, 나중에 한번 해보고 말을 해야 할 것 같다. 
(특히, SRAM 문제, Cache도 SRAM에 포함되며, 설정에 따라 SRAM 사용구조가 변경)

https://blog.espressif.com/understanding-esp32s-security-features-14483e465724




ESP32-S2 Secure Boot