2015年8月28日

ESP8266のSSL clientについて

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ESP-WROOM-02でhttpsなAPIを叩こうとしたらハマったので、まとめておきます。

SDKは1.3.0 (Release date: Aug 08, 2015)を使用しています。
ドキュメントも、これ(esp_iot_sdk_v1.3.0_15_08_08.zip)に含まれている2C-ESP8266__SDK__Programming Guide__EN_v1.3.0.pdfを参照しました。

現状

8/28現在、Arduino core for ESP8266はSSL(TLS)でのclientに対応していない。
対応して欲しいという要望&対応したいねという話は出ている。

ESP8266のSDKとしては、SSLに対応している。
※ただし、制約あり(この下に書きます)

処理の流れ

公式によるサンプルコードがEspressifのフォーラムにあるので、それを見るとだいたい分かります。

以下も非常に参考になります。
DSAS開発者の部屋:ESP8266 モジュールの AT コマンドに SSL クライアント機能を追加する
ESP-WROOM-02で、IFTTTをhttps(SSL/TLS)で呼び出す例 - Qiita

大雑把な流れとしては...

//証明書ストアを用意
unsigned char *default_certificate;
unsigned int default_certificate_len = 0;
unsigned char *default_private_key;
unsigned int default_private_key_len = 0;

//espconn, _esp_tcpを定義

LOCAL struct espconn user_tcp_conn;
LOCAL struct _esp_tcp user_tcp;

//接続先のIPアドレスとポートを設定
user_tcp.remote_ip[0] = 192;
user_tcp.remote_ip[1] = 168;
user_tcp.remote_ip[2] = 1;
user_tcp.remote_ip[3] = 128;
user_tcp.remote_port = 443;

//自分のポートを設定
user_tcp.local_port = espconn_port();

//type, state等を設定
user_tcp_conn.proto.tcp = &user_tcp;
user_tcp_conn.type = ESPCONN_TCP;
user_tcp_conn.state = ESPCONN_NONE;

//接続時、再接続時、接続断時のコールバックを設定
espconn_regist_connectcb(&user_tcp_conn, user_tcp_connect_cb);
espconn_regist_reconcb(&user_tcp_conn, user_tcp_recon_cb);
espconn_regist_disconcb(&user_tcp_conn, user_tcp_discon_cb);

//SSLバッファサイズを設定
espconn_secure_set_size(ESPCONN_CLIENT,5120);

//接続する
espconn_secure_connect(&user_tcp_conn);

みたいな感じ?

user_tcp_connect_cb()関数の中でデータ送受信時のコールバックを設定してあげれば良いみたい。

void user_tcp_connect_cb() {
    espconn_regist_recvcb(pespconn, user_tcp_recv_cb);
    espconn_regist_sentcb(pespconn, user_tcp_sent_cb);
}

サーバからの応答は
void user_tcp_recv_cb(void *arg, char *pusrdata, unsigned short length)
のpusrdataに入ってくるので、これを出力するなり判定するなりすると良い。

SSLバッファサイズはデフォルト(espconn_secure_set_sizeを呼ばない場合)で2048バイトになっているので、SSLパケットが2048バイトを超えそうな時は適宜増やしてね、ということらしい。
最大8192バイトらしいけど、8192を設定したらメモリに乗り切れないっぽくて(確保できない?)、espconn_secure_connectの段階でこけました。
公式サンプルコードにあるように5120くらいが限界かな...?

使用できるプロトコル(バージョン)と暗号

たぶん、ここが一番重要で、メモリ周りとかは全然大丈夫だけどespconn_secure_connectした直後にuser_tcp_discon_cbが呼ばれる(接続断される)ような、とあるサービスのAPIサーバがあって、Wiresharkでパケットキャプチャしたら原因が分かりました。

こちらがESP8266からサーバに送信されたClient Hello。


バージョンはTLS 1.1で、Cipher Suitesは以下の4種。

  • TLS_RSA_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_RC4_128_SHA
  • TLS_RSA_WITH_RC4_128_MD5


TLS 1.1を拒否ってたり、上記暗号種での接続を拒否ってると


「お前の指定したバージョン、暗号種ではうちに繋げねーぞ」とHandshake Failureが返ってきてServer Helloしてくれない訳です。

HeartbleedとかPOODLEとか色々あった関係で、厳しめなところは繋がらないという感じかなぁ。

このマイコンの性能上、強度の高い暗号アルゴリズムは載せられないのでしょうが、IoT向けを前面に押し出してるからには、もうちょっと頑張ってほしい...

追記その後、Arduino core for ESP8266でWiFiClientSecureが追加され、httpsが叩けるようになりました。

0 件のコメント:

コメントを投稿

記事へのコメントはいつも確認している訳ではないので、お返事が遅れる場合があります。
ご質問やご意見は twitter@9SQ へお送り頂けると早くお返事できると思います。