ESP8266 + MicroPython で SSL してみる

(更新

Confirmed that MicroPython 1.8.4 on ESP8266 has (even limited) SSL support and could connect to google.com and also api.twitter.com by ‘https://’ prefix.

ESP8266 + MicroPython による SSL の情報をネット上で探してみたのですが、なかなかまとまった情報がなくて苦労しました。こういう場合は、「あまりにも自明なので情報がない」か「それはできない」ことが多いのですが、今回は「知っている人には自明なんだけど、初心者向けの情報が少ない」ということが敗因のようです。

結論から書きますと、MicroPython 1.8.4 (ESP8266) であれば制限付きながら SSL 可能のようです。

まず最初に、最低限のテストコードを示します。これは、MicroPython のソースコードを Git で取得すると、micropython/examples/network/http_client_ssl.py (以下、オリジナルサンプルコードと呼ぶ)にあるのですが、MicroPython のソースにアクセスするつもりでなければ、これを見つけるのは困難と思います。

テストコード

import usocket
import ussl
s = usocket.socket()
addr = usocket.getaddrinfo("google.com", 443)[0][-1]
s.connect(addr)
s = ussl.wrap_socket(s)
print(s)
s.write(b"GET / HTTP/1.0\n\n")
print(s.read(4096))

あくまでもテストコードですので、詳細は上記オリジナルサンプルコードを参照ください。以下に動作結果を示します。

なお、SSL にどんな制限があるか、については MicroPython のウェブサイトにもありますが、

  • Currently, this function does NOT validate server certificates, which makes an SSL connection established prone to man-in-the-middle attacks. (訳: 現在の実装では、この関数(usocket.wrap_socket())はサーバー側の証明書を検証しません。つまり、この SSL 接続には中間者攻撃への脆弱性があります。)

また、元になっている axTLS Embedded SSL のドキュメントによると、

  • The axTLS project is an SSL client/server library using the TLSv1 protocol.

とありますが、通信相手の SSL 実装や設定によっては、うまく接続できないこともあるようです。詳細は、axTLS のドキュメントやソースコード等に当たる必要がありそうですが、いまのところ、google.com や api.twitter.com には SSL 接続できているようなので、ちょっとした IoT の実験には使えそうです。

時間が取れたら、ESP8266 から直接 tweet するボットなど書いてみようと思っています。本当は MicroPython が OAuth のライブラリをサポートしてくれていると良いんですが、、、どこかでコンパクトな実装を探してくるか、サブセットを自前で実装しようかと思っています。

おまけ

現状の公式サイトには情報がないので obsolete(時代遅れ)なのかも知れませんが、MicroPython (ESP8266) 1.8.4 では、urequests  というライブラリが入っているようです。

import urequests
urequests.get('https://google.com')

のように使え、https://github.com/micropython/micropython-lib/blob/master/urequests/urequests.py というコードを読むといろんなことができそうですが、なにぶんドキュメントが無いようなので、at your own risk ということのようです。

補足(2016/10/02)

補足ですが、MicroPython のうち、wipy アーキテクチャ(TI CC3200 ベースらしい)向けの SSL は上記と異なるようです。詳しくは、Git したソースコードで micropython/docs/library/ussl.rst を御覧ください。中に、only:: not port_wipy とか only:: port_wipy という記述があり、後者が wipy ポート用で、前者がそれ以外用、ということのようです。