ESP」タグアーカイブ

ESP8266のWiFiClientSecure系でcertを扱う時のメモ

今、調べながら試しているけどchatgptに存在しないメソッド言われたりと騙されるっぽいのでメモを残す。終了

ESP8266(ESP-WROOM-02)の内容。ESP-WROOM-32ではないので注意。

環境

  • Windows11
  • Arfuino IDE 2.3.1
  • esp8266 by ESP8266 Community 3.1.2(レポジトリ)

動きそうなやつ(これから確認、動いたら記事修正する)

WiFiClientSecureBearSSL#setInsecure

基本こちらのまんまで動いた。(リンク先はESP8266でなくESP32なので他を参考にするときはクラス仕様違うので注意)

最初は戻り値にバイト数とか入ってたけどサーバ側でcontents-length指定していないのが原因だった。

BearSSL_Validation.ino

Example->Esp8266Wifiの中にいるサンプル。

単独のCAをツールでヘッダーファイルに変えて読み込むやつだと思う。

includeで気になった奴

#include <StackThunk.h>というのがある。(実装のcpp

StackThunk.c - Allow use second stack for BearSSL calls


  BearSSL uses a significant amount of stack space, much larger than
  the default Arduino core stack. These routines handle swapping
  between a secondary, user-allocated stack on the heap and the real
  stack.

BearSSLはスタックすごい使うからうんぬんと。通常のスタックだと足りないから、ヒープを使ってごにょごにょしてくれるらしい。

サンプルソースだと割り当て関連の機能は使っておらず使用量確認のみに見えるけど中で読んでいるかも。一見、足りてそうに見えるときも内部でこいつが使い切ってるとかはあるかもしれないので心に留めておく。

事前準備

cert.pyを使用して証明書のデータを更新。(長くなったのでこちら

フィンガープリントだけで接続

フィンガープリント設定すればとりあえずつながる。

何もないよりましだといっている

The SHA-1 fingerprint of an X.509 certificate can be used to validate it
instead of the while certificate.  This is not nearly as secure as real
X.509 validation, but is better than nothing.  

自己署名証明書で接続

allowSelfSignedCertすればOKとのこと。

こいつは自己署名は誰でも作れるから注意を(略

It is also possible to accept *any* self-signed certificate.  This is
absolutely insecure as anyone can make a self-signed certificate.

ハードコード公開鍵で接続

公開鍵をハードコードしておいてそいつを使って(通常のSSLは認証プロセスを飛ばして)通信できる。一般公開しないサービスならこれでもよさそうな気がする。

The server certificate can be completely ignored and its public key
hardcoded in your application. This should be secure as the public key
needs to be paired with the private key of the site, which is obviously
private and not shared.  A MITM without the private key would not be
able to establish communications.

certをハードコード方式(多分一番固い)

certをハードコードして検証する方式。

有効期限チェックはするけれどもCRLはサポートしていないらしい。発行された証明書が有効期限内に無効化されていてもチェックされない。自己署名証明書をルートにしたチェーンも作れるらしい。

A specific certification authority can be passed in and used to validate
a chain of certificates from a given server.  These will be validated
using BearSSL's rules, which do NOT include certificate revocation lists.
A specific server's certificate, or your own self-signed root certificate
can also be used.  ESP8266 time needs to be valid for checks to pass as
BearSSL does verify the notValidBefore/After fields.

上のようにcertをルート証明書にしても動くはずだがレスポンスとりそびれるときがあるのに気づいた。ルートじゃなくてサーバのcertを使っているときも取りそびれ発生しているかもしれない。原因調査未。とり急ぎ調査はおいておいて他の方式の確認進める。と、思ったら方式別でも発生している。=> 解決方法

暗号化方式の選択

早さ優先したいときとか

client.setInsecure();

ノーチェック

client.setCiphersLessSecure();

以下のやつら指定(と思う)

// For apps which want to use less secure but faster ciphers, only
  static const uint16_t faster_suites_P[] PROGMEM = {
    BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
    BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
    BR_TLS_RSA_WITH_AES_256_CBC_SHA,
    BR_TLS_RSA_WITH_AES_128_CBC_SHA };
  • BR_TLS_RSA_WITH_AES_256_CBC_SHA256: RSA鍵交換、AES-256-CBC暗号、SHA-256ハッシュ
  • BR_TLS_RSA_WITH_AES_128_CBC_SHA256: RSA鍵交換、AES-128-CBC暗号、SHA-256ハッシュ
  • BR_TLS_RSA_WITH_AES_256_CBC_SHA: RSA鍵交換、AES-256-CBC暗号、SHA-1ハッシュ
  • BR_TLS_RSA_WITH_AES_128_CBC_SHA: RSA鍵交換、AES-128-CBC暗号、SHA-1ハッシュ
自分で指定

使えるリストはおそらくこちら。(さらに制限かかっているかもしれないが細かくは追っていない)

ちなみにサンプルソースのwww.example.comはsha1のBR_TLS_RSA_WITH_AES_256_CBC_SHAとBR_TLS_RSA_WITH_AES_128_CBC_SHAは通じたがsha256では通じなかったので上の指定だと接続エラーになった。

つなげるサーバの証明書を取得

こちらを参照

変数名サンプルソースと違うので適宜修正

BearSSL_CertStore.ino

モジラから読み込んだルートcaを複数ストアして使えるやつっぽい。容量気にしない状況ならこいつが使いやすそう。

証明書の更新

長くなったのでこちら

証明書のアップロード

初めにアップロード用ツールのインストール。(手順はこちら

IDEから[Ctrl] + [Shift] + [P]から ‘Upload Little FS to Pico/ESP8266‘ を選択し、(リセットボタン押したりするプログラム書き込みモードで)アップロード実行。

手順の方にも書いたけどシリアルモニター開いていると競合して書きこめないので注意

動作確認

サイトのドメイン入れて実行。大体の場合、htmlソースの表示がレスポンス待ち処理が足りなくてされない。 解決方法

課題

Upload LittleFSだとファイルシステムがすべて上書きされるらしい。一部差し換え的なことがやりたい。ファイルシステムルート直下のcerts.idxとcerts.arを差し替えたらよさそうだがcerts.idxがどこでできているのかまだ理解していない。CertStore::initCertStoreの中でcerts.idx作成しているのでcerts.arだけさしかえればよさそう。失敗したら接続できなくなりそうだけど、ネット越しにファイル放り込んで再起動とかもできそうかな。

ESP8266HTTPClientへの連携

以下の感じでcertを設定済みのWiFiClientSecureをHTTPClient のbeginメソッドに渡してやると動いた

以下蛇足

Chatgptに言われたけどなさそうな奴

無いっぽい奴1

とchatgptにいわれた。が、

C:\Users\kitam\Desktop\https\https.ino: In function 'void setup()':
https:32:10: error: 'class BearSSL::WiFiClientSecure' has no member named 'setCACertBundle'
   32 |   client.setCACertBundle(x509_crt_bundle);
      |          ^~~~~~~~~~~~~~~
exit status 1
'class BearSSL::WiFiClientSecure' has no member named 'setCACertBundle'

ないよと。ソース見ると確かにいない。なお、ESP32ならこれで動く模様。(参考

無いっぽい奴2

といわれたが、同じように

C:\Users\kitam\Desktop\https\https.ino: In function 'void setup()':
C:\Users\kitam\Desktop\https\https.ino:32:9: error: 'class BearSSL::WiFiClientSecure' has no member named 'addServerKey'
   32 |  client.addServerKey(x509_crt_bundle);
      |         ^~~~~~~~~~~~

exit status 1

Compilation error: 'class BearSSL::WiFiClientSecure' has no member named 'addServerKey'

addServerKeyはぱっとみESP32のライブラリにもなさそうなのでchatgptがどこから拾ってきたかよくわからない。

おばけくるましーんのメモ

寝ない幼児を脅すために、リモコン操作で扉とかをガタガタさせたい。

通信はそこそこ距離が届きそうなESPNow使う。(ESPNow調べた時の記事)

揺らす道具は130モーターに何かつけて自作した振動モーター+ESP32-DevKit。DevKit高いけどとりあえず。

リモコンはM5StickC。こいつも高いけどどんな機能必要になるかわからないので手軽にいじれるやつで。

電池と手持ちの部品で動かすには突入電流が大きい(参考)のでコンデンサが足りなかった。コンデンサ100uFぐらいだとパチモンのDCDCでは2.7vぐらいまで、パチモン及び正規品レギュレーターでも2.8vぐらいまでおちる。レギュレーターだと半々の確率でESP起動まではいけることが多いけどモーターを回すとまあだめ。とりあえずコンデンサ大き目ぽちって待機。

今のプログラムはこれ

ハードは

電源の3.3VからESPの3.3vピン、電源グランドからGND

GPIO2-抵抗 – 動作確認用のLED -GND

GPIO15-抵抗 – 2SK4017のBase -GND

電源ライン – モーター – 2SK4017

あとはコンデンサやら帰還ダイオードやらざっくり

USBコンセント電源から5vでとったら動作するので追加コンデンサでも厳しかったら揺れるとこ(モーター)だけ扉につけるように半分離するとよいかも。(電池動作の動作確認機を兼ねているので極力電池で頑張る)

ESP-Nowの公式サンプルが動かなかったので調査

環境

  • ESP32-DevKitC V4 × 2個(MasterとSlave)
  • Arduino IDE (Windows Store 1.8.57.0)
  • ボード ESP32 Dev Module(ESP32 Espressif Systems v 1.0.6)

使用サンプル

ESP32 Dev Moduleの「スケッチ例」->「ESP32」->「ESPNow」->「Basic」のMaster/Slaveのセット

\ArduinoData\packages\esp32\hardware\esp32\1.0.6\libraries\ESP32\examples\ESPNow\Basic の MasterとSlave

発生エラー

Slaveのpeerにデータを送るタイミング(esp_now_send)で「違うチャンネルには送れないよ!」と怒られる。

E (838684) ESPNOW: Peer channel is not equal to the home channel, send fail!
Send Status: Invalid Argument

原因

文字通り違うチャンネルには送れないみたい。公式サイトになんとなくそれを前提としていそうなことは書いてあるけど明示してある箇所は見つけていない。(メッセージがそのままなのでまぁ間違いはないんだろう。)ここらみると2020年の冬ぐらいの1.0.5-rc2で変わったのかな?

For example, the destination device doesn’t exist; the channels of the devices are not the same

Masterは自分がDefaultの1チャンネルになっていて送信想定が3チャンネルになっているので引っかかっている。(それはそれとしてサンプルのSlaveはチャンネルが1になっているのにMasterのソースでは3を指定しているのでそこでも不整合が生じている)

対処

チャンネルを合わせればよい。

1chで上げる場合

Slaveは1チャンネルで上がっているので、送信想定を1にしてやればよい

define CHANNEL 1

slave.channel = CHANNEL;

その他チャンネルで上げる場合

Master/Slaveのチャンネルを任意(使用可能は1~13)に指定してやればよい。

Slave(APモード)のチャンネル指定

Slaveは(違和感あるけど)APモードになっていてSoftAP立ち上げの際に指定できる。

define CHANNEL 1 // からの
 bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0);

Master(STAモード)のチャンネル指定

MasterはSTAモードになってる。ここをみるとSTAモードのときはsoft-APもstationモードと一致するらしい。(で。ドキュメントで確認できていないけどESPNowもsoft-APの設定使って動いているみたい。Espressif だとソース見れないみたいだけどM5Stackの方では派生したもの?みれるようなのでそっち追えばわかるかも)

3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP32 station.

指定方法の正しい作法はわからなかった。動いたのは以下の操作。

#include <esp_wifi.h>// して

void setup() {
 //の
  WiFi.mode(WIFI_STA);
 // した後に
  esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE); // チャンネルを指定してあげる

その他

チャンネルについて

2.4 GHz 帯の中で微妙に周波数変えて周波数ごとにデータ送るやつ。こことかわかりやすい。日本だと1-13チャンネル使えてESPも1-13指定できる。(多分同じ奴だと思うけど調べてない)チャンネル近いと干渉するので、既存の機器と重なったりしたら変えてみると幸せかもしれない。

少し上のWIFI_SECOND_CHAN_NONEについて

「チャンネル2つ使うとデータが倍の勢いで送受信できる」ってやつを使うかどうかの選択パラメータで使わない(HT20)を指定している。使う(HT40)指定のWIFI_SECOND_CHAN_ABOVEとWIFI_SECOND_CHAN_BELOWもあるけどESPNowには多分反映されないでWifiの方だけにかかわると思う。(とりあえず速さいらんと思うのでちゃんと調べてはいない)