はじめに
以前作成したM5Stackの通信アプリを2年ほど運用してきて、改修の必要がありビルドし直したところ、これまで動いていたアプリが動かなくなってしまいました。(M5Stackあるある)
アプリはWebSocket通信を行うものですが、認証用のトークンの取得/更新のhttpsリクエストを行い、モノの管理やログ出力にMQTTを使っています。最大3つのhttpsセッションを張ることがあります。
M5Stackのライブラリーが更新されたことで、メモリー不足になってしまいました。特にWiFiClientSecure+mbedTLSでだいたい90Kbyteくらい空きのヒープが必要なようです。
これは build_flags = -DCORE_DEBUG_LEVEL=5 を指定して詳細なログを出力させないとわかりませんでした。
回避策
今回は運用中のアプリということもあり、時間が限られる中の対応となりました。結論を言えば、mbedTLSの代わりに SSLClient ライブラリーを使用しました。
PubSubClient
MQTTには PubSubClient を使用していたので、WiFiSclientSecureに代えてSSLClientを指定します。
WiFiClientSecure https_client;
PubSubClient mqtt_client(https_client);
WiFiClient base_client;
SSLClient https_client(base_client, TAs, (size_t)TAs_NUM, rand_pin);
PubSubClient mqtt_client(https_client);
SSLClient
httpsのPOSTリクエストはWiFiClientSecureライブラリーだと簡単に記述できますが、SSLClientは少しコード量が増えます。
SSLClientは証明書に代えて、TrustAnchors を使用します。 BearSSL Trust Anchors Generator のWebサイトで生成することができますので、これをincludeして利用します。
まとめ
結果、なんとか3つのセッションのうち2本をSSLClientに切り替えることで、応急処置することができました。空きのヒープは少し増えましたが、ファームウェアのサイズ(フットプリント)は少し増えました。
現時点でSSLClientはTLS1.3にはまだ対応していなかったり、どこかのタイミングで改めて見直しが必要になるかもしれません。
2023/12/31追記
しばらく運用していると下記のようなエラーが出力されて接続できなくなりました
20:53:51.515 -> (SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
20:53:51.515 -> (SSLClient)(SSL_WARN)(m_run_until): Terminating because the ssl engine closed
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_start_ssl): Failed to initlalize the SSL layer
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_print_br_error): Certificate is expired or not yet valid.
イシューがありました。時刻の表記の問題らしい。
https://github.com/OPEnSLab-OSU/SSLClient/issues/27
unsigned long RTCTime = time(nullptr);
sslClient.setVerificationTime((uint32_t)((RTCTime / (SECS_PER_DAY)) + 719528UL), (uint32_t)(RTCTime % (SECS_PER_DAY)));