セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Provision)

#はじめに#
2019年5月に[IoTLT](https://iotlt.connpass.com/)にてLTをさせていただきました。
その内容のフォローを記入しながら自分なりに整理していきたいと思います。

発表内容：
[スタートアップIoTデバイスのセキュリティを考える](https://www.slideshare.net/KentaroMitsuyasu1/iot-144602008)

#前回までのあらすじ#
[セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Configure)](https://qiita.com/kmitsu76/items/a37f285d4f2eff377f66)でATECC608Aを使用するための初期化と、デバイスの秘密鍵に対応する公開鍵を抽出するところまで行いました。

今回の記事に関連するソースコードは下記にて公開中。
[kmwebnet/ECC608-Provision](https://github.com/kmwebnet/ECC608-Provision)

#テスト自己認証局の作成#
上記github上のPython スクリプトを利用し、手元にテスト自己認証局を作成。

ルートCAの作成
中間CAの作成
デバイス証明書の作成

上記の順番で行っていく。
Python の環境はWindows10 で作成。
以下を参考にさせていただきました。
[Anaconda で Python 環境をインストールする](https://qiita.com/t2y/items/2a3eb58103e85d8064b6)
インストール後、”scripts”内に移動し、下記を実行。

```
pip install -r requirements.txt
```

■ルートCAの作成
以下コマンドでルートCAを作成する。対話式なので任意の組織名とコモンネームを入れる。

```
Anaconda Powershell Prompt
(base) PS>python.exe .\create_root.py

Root CA key
    No key file found, generating new key
    Saving to root-ca.key

Generating self-signed root CA certificate
organization name:testcorp
common name:rootca.testcorp.com
    Saving to root-ca.crt

Done
```
これで、ルートCA証明書：root-ca.crt ルートCA秘密鍵：root-ca.keyができた。

■中間CAの作成　対話式なので任意の組織名とコモンネームを入れる。
上と同じコモンネームにしないこと。

```
(base) PS>python.exe .\create_signer.py

Loading root CA key
    Loading from root-ca.key

Loading root CA certificate
    Loading from root-ca.crt

Signer CA key
    No key file found, generating new key
    Saving to signer-ca.key

Generating signer CA certificate from CSR
organization name:testcorp
common name:signerca.testcorp.com
    Saving to signer-ca.crt

Done
```

■デバイス証明書の作成
[セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Configure)](https://qiita.com/kmitsu76/items/a37f285d4f2eff377f66)で最後に表示された以下公開鍵を"public_key.pem"などとして保存しておく。

```
-----BEGIN PUBLIC KEY-----
MFk…
…eB6g==
-----END PUBLIC KEY-----
```
同様に前回出力された結果の"Serial number"の値をコモンネームとして使うこととする。

```
(base) PS>python.exe .\create_device.py --devicekey public_key.pem

Load Device Public Key
    Loading from public_key.pem

Load Signer
    Loading key from signer-ca.key
    Loading certificate from signer-ca.crt

Create Device Certificate
organization name:testcorp
common name:0123xxxxxxxxxxxxee
    Save Device Certificate to device.crt
    Save Root Public Key to root-pub.pem

Done
```

■証明書定義コードの生成
今回作成した証明書に対応した、証明書内の各要素を構造体にした定義コード(cert_chain.c)を生成する。

```
(base) PS>python.exe　.\cert2certdef.py --signer-cert signer-ca.crt --device-cert device.crt
```

■証明書ヘッダーファイル作成
今回の証明書を変数へ代入するヘッダーファイル(provision.h)を作成する。

```
(base) PS>python.exe .\export_header.py
```

■作成完了時のイメージ
以下の通りのディレクトリ構造になる。
後ほどのhttps接続テストで使用するファイルは

ソースコードへ追加してコンパイル：
cert_chain.c
provision.h
root-ca.crt

httpsサーバー側へ設定する証明書
root-ca.crt
signer-ca.crt

となる。

```
    ディレクトリ: C:\Users\johndoe\python


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2019/06/10      8:14                __pycache__
-a----       2019/06/12     10:03          24411 cert2certdef.py
-a----       2019/06/12     10:03          11548 cert_chain.c
-a----       2019/06/10      8:20           7522 create_device.py
-a----       2019/06/10      8:04           5556 create_root.py
-a----       2019/06/10      8:14           5737 create_signer.py
-a----       2019/06/10      8:26            631 device.crt
-a----       2019/02/14      6:21           3738 export_header.py
-a----       2019/06/10      8:28           6229 provision.h
-a----       2019/06/09      8:25            180 public_key.pem
-a----       2019/06/11     19:32           2904 README.md
-a----       2019/06/11     18:18             41 requirements.txt
-a----       2019/06/10      8:06            607 root-ca.crt
-a----       2019/06/10      8:05            241 root-ca.key
-a----       2019/06/10      8:26            178 root-pub.pem
-a----       2019/06/10      8:14            680 signer-ca.crt
-a----       2019/06/10      8:14            241 signer-ca.key
```


#デバイスへの証明書の書き込み#
プロジェクト内"src"内へ
cert_chain.c
provision.h
を配置し、コンパイルしてデバイスで実行させる。
以下のように、デバイス内へ書き込みを行った後、再度読み出しを行い
ベリファイが行われ、問題がなければ以下のような結果が得られる。
これでデバイス側の準備が完了となる。

```
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 05:36:32
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=0x08578 ( 34168) map
I (105) esp_image: segment 1: paddr=0x000185a0 vaddr=0x3ffc0000 size=0x02048 (  8264) load
I (108) esp_image: segment 2: paddr=0x0001a5f0 vaddr=0x40080000 size=0x00400 (  1024) load
I (113) esp_image: segment 3: paddr=0x0001a9f8 vaddr=0x40080400 size=0x05618 ( 22040) load
I (130) esp_image: segment 4: paddr=0x00020018 vaddr=0x400d0018 size=0x16ca4 ( 93348) map
I (163) esp_image: segment 5: paddr=0x00036cc4 vaddr=0x40085a18 size=0x03664 ( 13924) load
I (174) boot: Loaded app from partition at offset 0x10000
I (174) boot: Disabling RNG early entropy source...
I (175) cpu_start: Pro cpu up.
I (178) cpu_start: Starting app cpu, entry point is 0x400816dc
I (0) cpu_start: App cpu up.
I (189) heap_init: Initializing. RAM available for dynamic allocation:
I (196) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (202) heap_init: At 3FFC3790 len 0001C870 (114 KiB): DRAM
I (208) heap_init: At 3FFE0440 len 00003BC0 (14 KiB): D/IRAM
I (214) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (221) heap_init: At 4008907C len 00016F84 (91 KiB): IRAM
I (227) cpu_start: Pro cpu start user code
I (245) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (806) ECC608: Serial Number:
0123xxxxxxxxxxxxee
I (806) ECC608: Revision Number:
I (806) ECC608: 00
I (806) ECC608: 00
I (806) ECC608: 60
I (806) ECC608: 02
I (806) 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
Writing Root Public Key
Writing Signer Certificate
Writing Device Certificate
Reading Signer Certificate
Comparing Signer Certificate
Reading Device Certificate
Comparing Device Certificate

Device Provisioning Successful!
```