蟹さんのBare MetalでBearSSL

IoTといえどもインターネットにつなぐのであれば、SSL(TLS)は必須な時代になったので、[蟹さん](https://qiita.com/yamori813/items/c1d8111a3f45c5a74655)もSSLを話せるようにしてみました。

[前にも書きました](https://qiita.com/yamori813/items/2d4d88d41a7d9618522b)がaxTLSがいまいちだったので調べていたら[BearSSL](https://bearssl.org/)という新しい実装が見つかり、これをポートする事にしました。

SSL通信はTCP通信の中を通すように作られています。

![SSL.png](https://qiita-image-store.s3.amazonaws.com/0/104066/676ab960-9475-db2a-e5eb-31c016bcfc3c.png)

BearSSLはもちろんCで書かれたライブラリなのですが、独自のプリプロセッサーを使ってCコードを生成している部分もあります。プリプロセッサーはCSで書かれていて、Windowsのバイナリのみの提供になります。

BearSSLはシステム依存が時間と乱数しか無くEmbedな環境にも非常に優しく出来ています。axTLSではソケットのread/writeがハードコードされてしまっていますが、BearSSLでは関数渡しで自前のコードが使えるようになっています。

乱数はもともとUNIX用とWindows用のコードが用意されているのですが、Embedでは使えないのでMT19937のコードを入れてみました。

時間はtime()関数が必要なのですが、BearSSLと自前のコードで読み込むヘッダーが違っていてtime_tが4バイトと8バイトになってしまい、X509の時間のチェックがうまくできなくてちょっとはまりました。

BearSSLのサンプルのクライアントコードをベースにlwIPのRAW TCPコードと融合させてどうにか動くようになりました。

![BearSSL.png](https://qiita-image-store.s3.amazonaws.com/0/104066/5ce0b3fc-1776-021b-358c-79012eeda4c6.png)

入力処理の流れは以下のようになっています。

Etherパケット受信割り込み -> low_level_input() -> データをnetif.input()に渡す -> lwIPが処理 -> tcp_recv()で設定した関数が呼ばれる -> 受信データをローカルバッファに保存 --- BearSSLに設定したread関数でバッファデータを引き渡し -> ネゴシエーションなどはBearSSL内で処理され通信内容はbr_sslio_read()で読める

出力はリニアに処理されます。

br_sslio_write_all()で書く -> BearSSLが処理 -> BearSSLに設定したwrite関数 -> lwIP -> lwIPに設定したoutput関数でデバイスリングバッファに保存

![スクリーンショット（2018-03-23 12.55.10）.png](https://qiita-image-store.s3.amazonaws.com/0/104066/82bc5e6a-9cbb-940f-4e33-78d169e2e642.png)

tcpdumpでの通信内容

```
microserver % sudo tcpdump -i re0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on re0, link-type EN10MB (Ethernet), capture size 65535 bytes
09:54:04.457395 ARP, Request who-has 10.10.10.2 tell 10.10.10.2, length 46
09:54:04.457494 ARP, Request who-has 10.10.10.3 tell 10.10.10.2, length 46
09:54:04.457503 ARP, Reply 10.10.10.3 is-at 00:13:3b:12:81:04 (oui Unknown), len
gth 28
09:54:04.467366 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [S], seq 6509, win 
2144, options [mss 536], length 0
09:54:04.467410 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [S.], seq 100541135
4, ack 6510, win 65535, options [mss 536], length 0
09:54:04.477530 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [P.], seq 1:194, ac
k 1, win 2144, length 193
09:54:04.495526 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], seq 1:537, ack
 194, win 65535, length 536
09:54:04.495541 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], seq 537:1073, 
ack 194, win 65535, length 536
09:54:04.495548 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], seq 1073:1609,
 ack 194, win 65535, length 536
09:54:04.495554 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 1609:2060
, ack 194, win 65535, length 451
09:54:04.497594 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 537, win 2
144, length 0
09:54:04.497731 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 1073, win 
2144, length 0
09:54:04.749933 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], seq 1073:1609,
 ack 194, win 65535, length 536
09:54:04.757573 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 1609, win 
2144, length 0
09:54:04.757621 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 1609:2060
, ack 194, win 65535, length 451
09:54:04.757756 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 2060, win 
1693, length 0
09:54:04.767515 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 2060, win 
1693, length 0
09:54:05.236710 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [P.], seq 194:236, 
ack 2060, win 1693, length 42
09:54:05.337974 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], ack 236, win 6
5535, length 0
09:54:05.347562 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [P.], seq 236:279, 
ack 2060, win 1693, length 43
09:54:05.347944 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 2060:2066
, ack 279, win 65535, length 6
09:54:05.643961 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 2060:2103
, ack 279, win 65535, length 43
09:54:05.647583 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 2103, win 
1650, length 0
09:54:05.649108 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [P.], seq 279:335, 
ack 2103, win 1650, length 56
09:54:05.649297 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 2103:2275
, ack 335, win 65535, length 172
09:54:05.657611 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 2275, win 
2144, length 0
09:54:05.657659 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [P.], seq 2275:2298
, ack 335, win 65535, length 23
09:54:05.701507 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [P.], seq 335:358, 
ack 2298, win 2121, length 23
09:54:05.701553 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [F.], seq 358, ack 
2298, win 2121, length 0
09:54:05.701583 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [.], ack 359, win 6
5535, length 0
09:54:05.701716 IP 10.10.10.3.8080 > 10.10.10.2.49153: Flags [F.], seq 2298, ack
 359, win 65535, length 0
09:54:05.707641 IP 10.10.10.2.49153 > 10.10.10.3.8080: Flags [.], ack 2299, win 
2120, length 0

```

09:54:05.647583までがネゴシエーションでこれ以降が実際の通信になります。

https://github.com/yamori813/rtlbm-mruby

もちろんmrubyから使えるようにするつもりですが、インターフェースはなにか有り物に似せて作ろうかとも思っています。

ポートして分かった事はCA(TA)をどう管理するかとある程度正確な時間が必要という事です。サンプルプログラムではTAをハードコードしてありますが、そのTAで認証できない証明書がサーバに貼られた場合はエラーになりますし、ある程度の柔軟性を持った仕組みが必要な気がします。時間についてはRTCをつむしかないかもしれませんね。

サーバー側が自分の管理下でオレオレ証明書で運用するのであればTAは固定でもよいかもしれないが、一般のサービスに接続する場合は証明書の発行元が変わる事も考えられTAの管理は柔軟にしなければいけない。

BearSSLって本当に素晴らしいです。