레이블이 OpenSSL인 게시물을 표시합니다. 모든 게시물 표시
레이블이 OpenSSL인 게시물을 표시합니다. 모든 게시물 표시

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 

11/10/2021

AWS FreeRTOS Provisiong 자료수집 및 이해

1. AWS Provisioning 관련자료 

AWS Provisiong 관련자료 수집중이며, 우선 전체 구조와 동작방식 및 관련내용 메뉴얼을 우선 숙지 후 관련내용 정리 

우선 이를 기본적으로 이해하기 위해서는 TLS를 반드시 알아야하며, ESP32에서 AWS FreeRTOS를 사용하지 않고,
FreeRTOS에서 AWS-SDK를 Porting하여 기본 테스트를 진행하였지만, 현재 사용하고 있는 곳에서는 SRAM이 부족하여 이를 사용하기가 힘들 것 같다. 
다만, 일반적인 ESP32에서는 충분히 사용가능하다. 

AWS의 Embedded SDK Components 사용법 
최근에 들어가보니, 소스가 많이 변경되어 있으며, Manual도 새로 업데이트가 되어있다.
진작에 올려놓을 것이지, 젠장 
component도 이전과 완전다르며, 가능하다면, 최신버전으로 사용하시길 


  • AWS Provisiong 용어정리 
AWS Provisioning 의 크게 X.509 CSR(Certificate Signing Request) 구분되어진다. 
CSR도 X.509의 일종이지만, X.509를 요청하여 받는 것이며, 포맷은 X.509와 거의 유사하다.
  1. Fleet Provisiong without certificates: CSR 기반으로 인증서가 없이 인증하는 방법으로 나오며 다시 2종류 분류 
  2. Provisiong with certificates: X.509를 Device에 내장하여 진행하는 것으로 다시 3종류로 분류구분  


  • Provisioning with certificates 
Device들은 Certificate와 Private Key를 가지고 있는 구조로 또 다시 각 3개의 방식으로 구분되어짐 
참고로 상위 이름은 내가 임의로 정하며 AWS에서는 별다른 용어를 사용안함 
 
  1. JITP(Just in Time Provisioning): AWS IoT Core 만 이용 
  2. JITR(Just in Time Registration):  AWS IoT Core 와 AWS Lamda 이용 
  3. MAR(Multi-Account Registration): AWS IoT Core 의 Account가 여러개 사용 

결정적으로 보면, AWS IoT Core 와 AWS Lamda를 사용 때문으로 판단
그리고 Account를 한개 혹은 멀티로 가는지로 구분  

1.1 Fleet Provisioning by Claim 

Device는 Claim cerficates 와 private key와 함께 제조되어 생산되어진다.
그리고, 이 기반으로  AWS IoT core에 접속하여 CSR로 다시 unique device certicate로 다운을 받아 인증을 받고 이를 등록 후 TLS통신시작되어진다.  

Port 8883

  • Claim-based의 문서를 보면 크게 두개로 분리
  1. Device에게 전달되기전 (CreateProvisiongTemplate를 만들고 이를 IoT Thing등록)
  2. Device에서 전달된 후, 즉 Device에서 진행할일 아래에 설명 (디바이스는 이곳만 확인)

  • Device에게 Claim Certificate 전달되기 전의 과정 및 설정  
AWS에서 설정해야 할것들이라고 보면 될것 같다. 
  1. create-provisioning-template:  template name 과 parameter 정의
  2. create-keys-and-certificate: claim certificate 와 key  active 모드 변경 
  3. create-policy: fleet provisioning 정책결정 CreateKeysandCerficate or CreateCertificateFromCsr 

  • AWS IoT 의 create-provisioning-template 설정확인
AWS IoT -> Connect -> Fleet provisioning templates 확인 
  1. Json에서 "PolicyName": "<provisioned-thing-policy>" :  아래의 이름으로 연결됨 
  • AWS IoT 의 create-policy JSON 설정확인
AWS IoT -> 보안 -> 정책 -> provisioned-thing-policy 확인 
  1. Json에서 둘중 하나로 결정 $aws/certificates/create-from-csr or $aws/certificates/create 설정


  • AWS IOT Endpoint
account-specific-prefix.iot.aws-region.amazonaws.com

  • Device에게 전달 된 후 진행될 일 (아래그림)
상위 그림을 간단히 요약하면, 처음 Claiim Certifcate 와 Key 기반으로 TLS로 MQTT로 AWS IoT를 접속하여 아래와 같이 두번의 절차를 진행 
  1. CreateKeysAndCertificate or CreateCertificateFromCsr 진행 
  2. RegisterThing진행 


https://d1.awsstatic.com/whitepapers/device-manufacturing-provisioning.pdf


  • MQTT의 TOPIC: Unique Device Certicate 와 Key Download
  1. $aws/certificates/create/json
  2. $aws/certificates/create/json/accepted
  3. $aws/certificates/create/json/rejected

MQTT CreateKeysAndCertificate
상위 TOPIC과 동일하며 Embedded C or C++ 예제는 현재없음(직접작성)

MQTT CreateCertificateFromCsr
상위 TOPIC중 create를 create-cert-csr로 변경, 예제참조가능하나 테스트 못함  

HTTP CreateKeysAndCertificate 
Fleet Provisiong는 미지원으로 파악되지만, 일반 Provisiong은 가능 (Owershiptoken이 필요)

  • MQTT 의 TOPIC : AWS Lamda 연결및  Provisiong Template
  1. $aws/provisioning-templates/{template-name}/provision/json
  2. $aws/provisioning-templates/{template-name}/provision/json/accepted
  3. $aws/provisioning-templates/{template-name}/provision/json/rejected

MQTT RegisterThing
상위 TOPIC과 동일하며, 이때 Device의 정보를 Parameter로 전달하고 Configuration 값을 받음

HTTP RegisterThing 
일반 Provisiong 에서 사용가능하나, Fleet Provisiong은 불가능 파악 (Ownership Token이 없음)

AWS MQTT API 

관련소스 Header 

PKC11의 전체구조
현재 PKC11의 필요성이 Token인데, 이 부분이 Ownership Token하고 관련이 있는지?? 


1.2 Fleet Provisioning by Trusted User

AWS IoT에 처음 접속할 때 Trusted User 경우에 사용한다고하며, 주로 End User/설치기술자가 될 때 사용한다고 한다.   
Claim 과 차이는 처음부터 CSR을 가지고 있지 않으며, Trusted User가 CreateProvisiongTemplate 함수를 이용하여 CSR와 CSR Key를 받으면, 상위 구조와 얼추 비슷하게 흘러간다. 

Claim 과 차이라고하면, CSR를 누가 갖고 있는냐고, 이기능은 AWS Lamda를 미사용 


https://d1.awsstatic.com/whitepapers/device-manufacturing-provisioning.pdf


AWS API (CreateProvisiongTemplate) HTTP로 구현 

CreateProvisiongTemplate 는 AWS CLI에서 어떻게 하는것으로 생각되어짐 


1.3 Fleet Provisiong PC기반 테스트 

  • Fleet Provisiong PC기반테스트 방법
  1. Create a provisiong temlate  (aws iot 로 진행)
  2. Create claim cirtificate and key (Claim 인증서/Key 생성)
  3. 상위 결과의 JSON에서  .certificateArn 값을 얻어옴 
  4. AWS IoT의 Policy를 claim certificate를 위해서 생성 및 이를 연결  
  5. Device에서 python code 로 fleet provision 진행 (Serial 과 Device 정보)
  6. fleet provisiong이 완료 후 이를 검증 
  7. mosquitto로 fleet provisiong 후 얻은 certificate와 key로 진행  (root.ca)


2. FreeRTOS AWS SDK Provisiong 관련자료 

  • CreateCertificateFromCsr: TOPIC도 가능하며, 예제참조 
Fleet Provisiong의 기본개념은 CSR을 이용하여 AWS IoT에게 X.509를 받아 저장 후 이를 기반으로 등록한 후 TLS통신을 하는 개념이다.  
이때 사용되어지는 것이 MQTT이며, 이를 이용하여 요청 및 인증서를 받는다. 


AWS MQTT Demo의 구성
AWS MQTT에서 내부적으로 Backoff 기능을 사용되는 것으로 파악(Back Off가 무엇인지?)
한글문서는 오타가 너무 많음(재미있는 것은 현재 ESP32는 MQTT QoS 1기반 TLS 이지만 아래는 QoS2 사용)  

AWS IoT Device SDK C 관련문서: Fleet Provisioning
현재 이상한 것은 이 관련된 함수는 AWS FreeRTOS에는 없는 것으로 파악 (API가 서로 다른 것으로 파악되며 최신꺼에도 아래 함수가 없어짐?? 선택?)
CSR기반으로 하는 인증 찾음 (관련 한글설명도 나옴)

CSR기반으로 하는 인증의 전체구조 
현재 Provisiong Library 없어진것으로 파악, 주의해야 함 (참조만 해야할 것 같음)


AWS MQTT Fleet Provisioning
MQTT Provisiong을 하는데, CSR을 사용하는 것으로 추측 

AWS FreeRTOS  관련문서 
AWS FreeRTOS와 상위 IoT Device의 소스에서 사용되는 함수 다르며, 이것도 글을 읽어보면 CSR기반??

AWS FreeRTOS Build 및 개발환경 (ESP32)
ESP-IDF가 전부 4.2기준으로 작성되며 이 부분 확인 

Fleet Provisioning 관련 정보
글을 읽다보면, CSR을 이용하여 동작이 되는 것 같으며, 이유는 ROM size를 줄이기 위해서 X.509를 사용하지 않는 것으로 보이는데, 전의 KCMVP 와 좀 다른 구조?
어째든 ECDSA 기반으로 구성되는 것으로 보임 

AWS 개발자 Guide로 CA 및 인증서 등록방법 추후 알아야 할 거 같음 

AWS CLI
GCP와 구조가 비슷한 것으로 보이며, 일단 이거 사용법은 나중에 알아야 할 거 같음



2.2 PKCS#11 의 이해

PKCS는 공개키 암호화 표준으로 AWS IoT에서 PKCS#11을 사용하며, 이곳에 Ceritificate를 보관하여 동작하는 구조이다.

PKCS(Public Key Cryptography Standards)

PKCS#11 (Cryptographic Token Interface Base Specification)
문서를 읽어보면, Smart Card, TPM(Trusted Platform Module), HSM(Hardware Security Module)에 사용되어진다고 하며,
Secure Key를 Storage에 저장하는 역할이라고 하며,
표준은 두 군데에서 진행하며 주로 보면 OASIS가 주체적으로 하는 것으로 보임



AWS corePKCS11 
AWS에서는 처음 PKCS11 Sessiong을 생성한 후 Cerficate와 Key를 PKCS11를 이용하여 RSA 혹은 ECDSA 방식 corePKCS11를 이용하여 Provising을 Flash Storage 저장한다.
이 PKCS11으로 저장된 Cerficate와 Key의 기반으로 Session을 만들어 TLS를 사용하여 접속진행
현재 ESP32 OpenSSL이 아닌 mbedTLS를 사용하는 구조임

xInitializePkcs11Session
SlotList를 가져오고, PKCS11 Login

Certificate 와 Key를 PKCS11으로 Provisiong 진행
provisionCertificate

provisionPrivateKey

Mbedtls_Pkcs11_Connect
Mbedtls_Pkcs11_Recv
Mbedtls_Pkcs11_Send


소스보면, Fleet Provisiong을 해보면 내부에 DER형식으로 Template으로 Certificate와 Key를 별도생성하는데,
이 API를 이용하며 RSA/ECDSA 방식으로 각 Certificate와 Private Key를 저장한 후 PKCS11 Session 기반의 TLS을 사용하는데,
일반적인 TLS와는 다른 방식으로 보인다.
현재로 보면 AWS에서 PKCS11는 필요할 것으로 보임

PKCS11
관련 한글자료


2.3 FreeRTOS의 AWS Provisiong 관련소스

현재 Embedded 용으로 파악되는 것은 아래와 같이 Provisiong을 위해서 두개의 OpenSource 이며
관련내용은 아래의 링크를 참조해서 파악하자.

  • AMAZON FREERTOS (AWS FreeRTOS)
Amazon에서 FreeRTOS기반으로 SDK가 포함되어져 만들었으며, Provisiong을 어떻게하는지 파악을 못함

  • AWS IoT Device SDK 관련소스 (Version에따라 구조가 다름)
AWS 에서 IoT를 위한 SDK로 MQTT는 QoS2 기반으로 TLS통신하는 것으로 파악되며, 현재 ESP32의 MQTT는 지원불가능??(ESP QoS1까지만 지원)
WSS로 사용할 경우에도 RootCA 설정하는 곳이 없음 

AWS IoT Device SDK 문서 

  • AWS Provisioning Python로 PC 테스트 용 (AWS CLI 필요)
PC에서 가장 손쉽게 테스트 하는 방법으로 상위 PC 테스트 Manual에서 aws cli 와 함께 진행

1/03/2021

Android System App 권한

1. Android App Signature

Android App에 Signature 기능이 있는 것을 알아본게 된 이유가 System 권한을 가지고 실행하기 위해서 이를 알아보게되었다. 
왜냐하면, 일반적으로 만든 App들은 untrusted_app domain으로 SELinux에서 제한이 있어 매번 제대로 실행이 되지 않는 것을 해결해볼까 하고 생각이였다.
물론 SELinux를 허용모드로 하면 이문제는 이 부분이 다 필요가 없지만, 개발환경이 아닌 실제에서는 다르기때문에 이를 다시 생각하게되었다. 

물론 이 문제이외에도 permission에 관련된 문제가 있었으나, 그부분은 init.xxx.rc에서 강제로 했다. 

이부분은 OpenSSL의 인증서 Certificate(X.509)부분을 보면 쉽게이해가 가며, 간단히 보면, private key 와 public key의 사용으로 동작되는 것을 알 수 있다. 

암호화 기본개념 과 Cipher Suite

Android에서는 아래의 4종류의 Key가 있다고 하며 역할은 아래와 같다. 
  1. platform: a key for packages that are part of the core platform.
  2. shared: a key for things that are shared in the home/contacts process.
  3. media: a key for packages that are part of the media/download system.
  4. testkey: the default key to sign with if not otherwise specified.

https://boundarydevices.com/android-security-part-1-application-signatures-permissions/

상위과 같이 동작원리는 간단하다. 
Signing/Verfify 로 이를 쉽고 빠르게 검증하는 것이다. 


AOSP Source 기준으로 살펴보면 각 Key 위치와 Certificate 위치확인 

  • Default build system signs package 들과 testkey 아래 위치에 존재
$ ls build/target/product/security/
Android.mk  media.x509.pem    networkstack.x509.pem  platform.x509.pem  shared.pk8       testkey.pk8       verity_key  verity.x509.pem
media.pk8   networkstack.pk8  platform.pk8           README             shared.x509.pem  testkey.x509.pem  verity.pk8

  • Vendor NXP(Freescale)용 signs package 
$ ls device/fsl/common/security/
media.pk8       networkstack.pk8       platform.pk8       README             shared.pk8       testkey.pk8                 testkey_rsa4096.pem
media.x509.pem  networkstack.x509.pem  platform.x509.pem  rpmb_key_test.bin  shared.x509.pem  testkey_public_rsa4096.bin  testkey.x509.pem

$ grep -r  PRODUCT_DEFAULT_DEV_CERTIFICATE. .
./device/fsl/imx6sl/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7d/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6sx/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx6dq/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx7ulp/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8m/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \
./device/fsl/imx8q/ProductConfigCommon.mk:PRODUCT_DEFAULT_DEV_CERTIFICATE := \

$ cat ./device/fsl/imx8q/ProductConfigCommon.mk  // OVERWRITE 
...
PRODUCT_DEFAULT_DEV_CERTIFICATE := \
	device/fsl/common/security/testkey
...

$ cat ./device/fsl/imx8q/BoardConfig.mk  // AVB를 위한 RSA 비대칭키사용
.....
BOARD_AVB_ENABLE := true

BOARD_AVB_ALGORITHM := SHA256_RSA4096
# The testkey_rsa4096.pem is copied from external/avb/test/data/testkey_rsa4096.pem
BOARD_AVB_KEY_PATH := device/fsl/common/security/testkey_rsa4096.pem
.......

$ cat ./device/fsl/imx8q/mek_8q.mk  
.....
# Copy rpmb test key and AVB test public key
ifeq ($(PRODUCT_IMX_TRUSTY),true)
PRODUCT_COPY_FILES += \
    device/fsl/common/security/rpmb_key_test.bin:rpmb_key_test.bin \
    device/fsl/common/security/testkey_public_rsa4096.bin:testkey_public_rsa4096.bin
endif
.....

PRODUCT_DEFAULT_DEV_CERTIFICATE 에 의해 overwrite가 가능하다고 하니, 상위와 같이 검색  

platform/shared/media/testkey 생성부터 인증관련내용

1.1 ASOP Source에서 platform Key 추출 

  • ASOP Default Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest1
$ cp build/target/product/security/platform.pk8 mytest1/
$ cp build/target/product/security/platform.x509.pem mytest1/

$ cd mytest1

//PKCS#08:  Private-Key Information Syntax Standard 로 아래와 같이 변경 (DER) platform.pem로 생성 
//PKCS#12:  Personal Information Exchange Syntax Standard 로 platform.x509.pem을 platform.p12로 변경  Private KEY는 platform.pem이용하고 설정값  

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android  

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

PKCSx(Public Key Cryptography Standards)
  1. PKCS_12:공개키 인증서 교환문법 표준
  2. PKCS_08:개인키 정보 문법 표준 


  • NXP용 Platform Key 추출 
두개의 password는 android로 설정 했으며, key alias는 androiddebugkey로 설정 
$ mkdir mytest2
$ cp device/fsl/common/security/platform.pk8 mytest2/
$ cp device/fsl/common/security/platform.x509.pem mytest2/

$ cd mytest2

$ openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem 
$ openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.p12 -password pass:android -name androiddebugkey 
$ keytool -importkeystore -deststorepass android -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass android 

$ ls 
platform.jks  platform.p12  platform.pem  platform.pk8  platform.x509.pem

Platform Key 추출


Platform Key 관련링크들  

2. App 에 System App 권한부여  

상위에서도 설명했지만, 기본 App은 untruested_app으로 실행되기 때문에 SELinux와 Permission 문제가 발생해서 이부분을 system 권한으로 변경하도록 실행 

  • Androidmanifest.XML 에서 system 권한 부여
Java에서 현재 root는 안된다고 하는데, 과거에는 된 것 같음 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.beep"
    android:sharedUserId="android.uid.system" >

  • ASOP에서 NXP platform.jks 추출 후 Android Studio 에서 Sign 방법 
Android Studio -> File -> Project Structure -> Signing Config


or 

Android Studio -> Build -> Generate Signed Bundle/APK -> APK

상위처럼 하면, 구지 build.gradle를 직접 수정하지 하지 않해도 되지만, debug 와 release를 구분해서 넣어주자.  


기본 SELinux Domain untrusted_app
[12387.628007] type=1400 audit(1611554077.764:163): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:untrusted_app:s0:c101,c256,c512,c768 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1 app=com.example.beep
바뀔 SELInux Domain system_app
[14697.359731] type=1400 audit(1611556387.500:167): avc: denied { read } for comm="om.example.beep" name="duty_cycle" dev="sysfs" ino=37724 scontext=u:r:system_app:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1

현재 permission 과 권한도 system으로 변경했지만 SELinux에서 거부되는 것은 현재 sysfs 때문이라고 생각이 된다. 

매번 Build Clean 후 다시 실행했으며, 만약 INSTALL_FAILED_SHARED_USER_INCOMPATIBLE 에러가 계속나면, 나의 경우, 상위 system 설정 후 Sign이 맞지않아 생겼다.
NXP용 platform key를 사용해야 문제가 없었음  

  • adb shell or serial 에서 package 설치확인 
Terminal에서  package 설치확인 
$ su
#
# pm list packages | grep <package>

# pm uninstall <package>


2.1 signapk.jar를 이용한 Sign 방법 

아직 해보지 못했으며, 관련부분만 현재 검색했음 

  • Android App Sign 
apk 생성후 이를 ASOP에서 직접 signapk.jar를 이용하여 sign하는 방법 
$ find . -name signapk.jar
./out/host/linux-x86/framework/signapk.jar
./out/soong/host/linux-x86/framework/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/combined/signapk.jar
./out/soong/.intermediates/build/make/tools/signapk/signapk/linux_glibc_common/javac/signapk.jar
./prebuilts/sdk/tools/lib/signapk.jar

$ mkdir mytest
$ cp my_nosign.apk   mytest/              // my app 
$ cp build/target/product/security/platform.x509.pem  mytest/
$ cp build/target/product/security/platform.pk8   mytest/
$ cp out/host/linux-x86/framework/signapk.jar  mytest/
$ cd mytest

$ java -jar signapk.jar platform.x509.pem platform.pk8 my_nosign.apk my_sign.apk        // signing apk 
$ ls my_sign.apk