#はじめに#
2019年5月にIoTLTにてLTをさせていただきました。
その内容のフォローを記入しながら自分なりに整理していきたいと思います。
発表内容:
スタートアップIoTデバイスのセキュリティを考える
#前回までのあらすじ#
セキュアなIoTデバイス通信をやってみた(ATECC608A概要編)でATECC608Aが、証明書をどう格納するか、
また、デバイスへの読み書き、署名、検証というコマンドを持っていることがわかりました。
#サンプルの分析とATECC608Aの組み込み方針決定#
Github:mbedtls-examplesがメーカーの用意したMbedTLSへのポーティング例になる。
この中身を分析し、ESP32でのATECC608Aの組み込み方法を検討したい。
mbedtls-examplesの内部は下記のようになっている。
cryptoauthlib:ATECC608Aを操作するライブラリ
mbedtls:MbedTLSのライブラリ
scripts:Pythonで証明書を作成するためのPythonコード
source:ポーティングを行う例のプログラム
cryptoauthlib,mbedtlsはさておき、sourceの中身を見てみる。
コード内部の動作概要は下記の通り。
cert_chain.c 署名者証明書、デバイス証明書の証明書定義を設定
cert_chain.h 上記のヘッダーファイル
configure.c ATECC608Aと通信し、コンフィグがロックされていなければコンフィグを書き込みロックする。
また、スロット0,2,3,7に秘密鍵を生成し、最後にスロット0の秘密鍵に対応する公開鍵を
Base64形式で出力する。
connect.c MbedTLSからATECC608Aを制御し、httpsにて通信テストを行う
mbedtls_config.h ATECC608Aが対応できる楕円暗号以外を無効にする
provision.c ATECC608Aへ証明書定義を使い証明書を書き込み、MbedTLSで使えるよう準備する。
tests.c テストを行う。
上記を基に、configure.c → provision.c → connect.cという流れで実装を行っていきたい。
#configure.cの実装#
ECC608-Configureにて最終のコートサンプルを公開。
上記の通り、configure.cでは、ATECC608Aと通信し、コンフィグがロックされていなければコンフィグを書き込みロックする。また、スロット0,2,3,7に秘密鍵を生成し、最後にスロット0の秘密鍵に対応する公開鍵をBase64形式で出力するプログラムになる。
■コンフィグについて
スロット0~15の使用方法を定義するコンフィグについて
スロットの設定については多岐にわたり、難しいが、今回のスロット0,2,3,7に
絞って解析してみる。
configure.c 47行目がATECC608A向けのコンフィグとなる。
ATECC508A CryptoAuthentication Device Complete Data Sheetの
2.2 EEPROM Configuration Zoneによると、この行のコンフィグは、16バイト目の"I2C_Address"から書かれているようだ。
20-51バイトがスロットコンフィグ、96-127がキーコンフィグとなる。
該当部分をわかりやすく抜き出し。
static uint8_t atecc608_configuration[] = {
0xC0, 0x00, 0x00, 0x01,
0x8F, 0x20, //Slot0:
0xC4, 0x44, //Slot1:
0x87, 0x20, //Slot2:
0x87, 0x20, //Slot3:
0x8F, 0x0F, //Slot4:
0xC4, 0x36, //Slot5:
0x9F, 0x0F, //Slot6:
0x82, 0x20, //Slot7:
0x0F, 0x0F, //Slot8:
0xC4, 0x44, //Slot9:
0x0F, 0x0F, //Slot10:
0x0F, 0x0F, //Slot11:
0x0F, 0x0F, //Slot12:
0x0F, 0x0F, //Slot13:
0x0F, 0x0F, //Slot14:
0x0F, 0x0F, //Slot15:
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x00, //Slot0:
0x1C, 0x00, //Slot1:
0x13, 0x00, //Slot2:
0x13, 0x00, //Slot3:
0x7C, 0x00, //Slot4:
0x1C, 0x00, //Slot5:
0x3C, 0x00, //Slot6:
0x33, 0x00, //Slot7:
0x3C, 0x00, //Slot8:
0x3C, 0x00, //Slot9:
0x3C, 0x00, //Slot10:
0x30, 0x00, //Slot11:
0x3C, 0x00, //Slot12:
0x3C, 0x00, //Slot13:
0x3C, 0x00, //Slot14:
0x30, 0x00, //Slot15:
};
2.2.1 SlotConfig (Bytes 20 to 51)の章から読み解くと以下となる。
0x8F, 0x20, //Slot0: 外部・内部署名有効、ECDH有効、PMS出力を隣のスロットへ行う:書込禁止
0x87, 0x20, //Slot2: 外部・内部署名有効、ECDH有効:書込禁止
0x87, 0x20, //Slot3: 外部・内部署名有効、ECDH有効:書込禁止
0x82, 0x20, //Slot7: 内部署名有効:書込禁止
2.2.5 KeyConfig (Bytes 96 through 127)の章から読み解くと以下となる。
0x33, 0x00, //Slot0: ECCキー、公開鍵生成可能、P256 NIST ECCキー、スロット個別ロック可能
0x13, 0x00, //Slot2: ECCキー、公開鍵生成可能、P256 NIST ECCキー
0x13, 0x00, //Slot3: ECCキー、公開鍵生成可能、P256 NIST ECCキー
0x33, 0x00, //Slot7: ECCキー、公開鍵生成可能、P256 NIST ECCキー、スロット個別ロック可能
意味が分からないものもあるが、KeyconfigでECCキーを使用するように設定しておかないといけないようだ。
■コマンドについて
ここでは特に、atcab_genkey_baseという関数がメインで使用されている。
atca_basic_genkey.cの解説によると以下の通り。
Issues GenKey command, which can generate a private key, compute public key, and/or compute a digest of a public key.
*
- \param[in] mode Mode determines what operations the GenKey
-
command performs.
- \param[in] key_id Slot to perform the GenKey command on.
- \param[in] other_data OtherData for PubKey digest calculation. Can be set
-
to NULL otherwise.
- \param[out] public_key If the mode indicates a public key will be
-
calculated, it will be returned here. Format will
-
be the X and Y integers in big-endian format.
-
64 bytes for P256 curve. Set to NULL if public key
-
isn't required.
- \return ATCA_SUCCESS on success, otherwise an error code.
modeは下記の定義により、秘密鍵を生成するのか、公開鍵を生成するのかを選択する。
define GENKEY_MODE_PRIVATE ((uint8_t)0x04)
define GENKEY_MODE_PUBLIC ((uint8_t)0x00)
public_keyを指定すると、そこに公開鍵が返ってくる。
今回スロット0のコマンドでpublic_keyが指定されている。
■動作させたイメージ
最後に”-----BEGIN PUBLIC KEY-----”と”-----END PUBLIC KEY-----”で囲まれた
公開鍵が生成され、出力される。
今後はこの公開鍵を使って認証局で署名し、デバイス証明書を作成し、デバイスへ書き戻す。
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5804
load:0x40078000,len:7924
load:0x40080000,len:5916
entry 0x40080314
I (29) boot: ESP-IDF 3.30103.190221 2nd stage bootloader
I (29) boot: compile time 07:27:44
I (29) boot: Enabling RNG early entropy source...
I (34) boot: SPI Speed : 40MHz
I (38) boot: SPI Mode : DIO
I (42) boot: SPI Flash Size : 4MB
I (46) boot: Partition Table:
I (50) boot: ## Label Usage Type ST Offset Length
I (57) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (72) boot: 2 factory factory app 00 00 00010000 00100000
I (80) boot: End of partition table
I (84) esp_image: segment 0: paddr=0x00010020 vaddr=0x3f400020 size=0x07b28 ( 31528) map
I (104) esp_image: segment 1: paddr=0x00017b50 vaddr=0x3ffc0000 size=0x0210c ( 8460) load
I (107) esp_image: segment 2: paddr=0x00019c64 vaddr=0x40080000 size=0x00400 ( 1024) load
I (111) esp_image: segment 3: paddr=0x0001a06c vaddr=0x40080400 size=0x05fa4 ( 24484) load
I (129) esp_image: segment 4: paddr=0x00020018 vaddr=0x400d0018 size=0x13a28 ( 80424) map
I (157) esp_image: segment 5: paddr=0x00033a48 vaddr=0x400863a4 size=0x02d40 ( 11584) load
I (167) boot: Loaded app from partition at offset 0x10000
I (168) boot: Disabling RNG early entropy source...
I (169) cpu_start: Pro cpu up.
I (172) cpu_start: Starting app cpu, entry point is 0x400816e0
I (0) cpu_start: App cpu up.
I (183) heap_init: Initializing. RAM available for dynamic allocation:
I (190) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (196) heap_init: At 3FFC31A0 len 0001CE60 (115 KiB): DRAM
I (202) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (208) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (215) heap_init: At 400890E4 len 00016F1C (91 KiB): IRAM
I (221) cpu_start: Pro cpu start user code
I (239) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (800) ECC608: Serial Number:
0123xxxxxxxxxxxxee
I (800) ECC608: Revision Number:
I (800) ECC608: 00
I (800) ECC608: 00
I (800) ECC608: 60
I (800) ECC608: 02
I (800) ECC608: Config Zone data:
01 23 xx xx 00 00 60 02
xx xx xx xx ee 01 35 00
c0 00 00 01 8f 20 c4 44
87 20 87 20 8f 0f c4 36
9f 0f 82 20 0f 0f c4 44
0f 0f 0f 0f 0f 0f 0f 0f
0f 0f 0f 0f ff ff ff ff
00 00 00 00 ff ff ff ff
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00
ff ff 00 00 00 00 00 00
33 00 1c 00 13 00 13 00
7c 00 1c 00 3c 00 33 00
3c 00 3c 00 3c 00 30 00
3c 00 3c 00 3c 00 30 00
-----BEGIN PUBLIC KEY-----
MFk.....
.......HJQ==
-----END PUBLIC KEY-----
Configuration Complete