電波状況の良くない場所からデータを送信する必要があったため、M5Stack BasicにLANモジュールを付けて有線でデータを送信することにしたんです。
データの送信先サイトがhttpsアクセスだったので、セキュアクライアントを使うプログラミングをしようと思ったところで気が付きました。
いままでESP32で使っていたWiFiClientSecureライブラリは名前の通りWiFi用だということに!
そのため、LANでセキュアクライアントが使えるライブラリを探すことになり、最終的に使うことにしたのがOPEnSLab-OSU/SSLClientです。
SSLClientはESP8266で馴染みのあるBearSSLベースのセキュアクライアントライブラリで、WiFiClientSecureでは面倒くさくてやる気が起きなかった証明書情報の取得作業を簡略化するサイトが用意されていたのが決め手になりました。
SSLClientで使う証明書情報の取得方法
SSLClientで使う証明書情報は次のサイトから取得することができます。
「Domains To Include」に、SSLClientでアクセスしたいサイトのドメイン名(ホスト名)を複数入力して、「Submit」ボタンを押すと...
このように、そのドメイン名の証明書を発行した認証局のルート認証局の証明書情報を含んだヘッダーファイルが表示されます。
この例では、ドメインにLINE Notifyの通知用APIサーバー(notify-api.line.me)とMachinistのデータ受信用サーバー(gw.machinist.iij.jp)を指定していて、両方のルート認証局がGlobalSignだったので1つの証明書情報が含まれたヘッダーファイルが表示されています。
ヘッダーファイルと言っているのは、表示された情報をプログラムから使うときにつぎのようにヘッダーファイルとして読み込むからです。
#include "trust_anchors.h" // アクセスするサイトのルート証明書情報
SSLClientのサンプルプログラムが 「trust_anchors.h」というファイル名を使用していたので、同じ名前を使っています。
WiFiClientとのサイズ比較
今回用意したテストプログラムのスケッチサイズとグローバル変数のサイズを比較した結果が次の表です。
WiFiClientSecureと比較してスケッチのサイズは132,504バイト(10%)も小さくなっていますが、グローバル変数が7,724バイト(3%)増えています。
スケッチサイズが約132Kバイトも違うっていうのはどういうことなんでしょうね。
グローバル変数のサイズが増えているのは、メディア用とセキュア用のクライアントオブジェクトを2つ作っていることが 影響しているように思います。
オブジェクトを作るプログラムは次のようになっています。
#ifdef USE_WIFICLIENTSECURE WiFiClientSecure client; #endif #ifdef USE_SSLClient WiFiClient wifi_client; SSLClient client(wifi_client, TAs, (size_t)TAs_NUM, 2); #endif #ifdef USE_ETHERNET EthernetClient ethernet_client; SSLClient client(ethernet_client, TAs, (size_t)TAs_NUM, 2); #endif
SSLClientの最後の引数「2」はGPIOの番号です。この番号をアナログ入力にして乱数発生用に使っているそうです。
この番号は何も繋いでいなくても大丈夫です。逆に使用した番号はデジタル出力など他の用途では使用できないので注意が必要です。
テストプログラム
テストプログラムは、LINEとMachinistに起動してからの経過秒数60秒ごとに送信するシンプルなものとなっています。
M5Stack Basicでは3種全て、ATOM LiteでWiFiClientSecureとWiFiでのSSLClientの動作確認をしました。M5Stackのライブラリは使用していないので、他のESP32搭載ボードでも動作すると思います。
SSLTest.ino
#define WIFI_SSID "2.4GHzのSSID" #define WIFI_PASS "2.4GHzのSSIDのパスワード" #define LINE_TOKEN "LINE Notifyのアクセストークン" #define MACHINIST_KEY "MachinistのAPIキー" #define MACHINIST_ID "MachinistのエージェントID" // コメントを外した行のライブラリが有効になります //#define USE_WIFICLIENTSECURE // ESP32の標準ライブラリを使う場合 #define USE_SSLClient // WiFiでSSLClientライブラリを使う場合 //#define USE_ETHERNET // M5Stack用LANモジュールを使う場合 #ifdef USE_WIFICLIENTSECURE #include <WiFiClientSecure.h> #endif #ifdef USE_SSLClient #include <WiFi.h> #include <SSLClient.h> #include "trust_anchors.h" // アクセスするサイトのルート証明書情報 #endif #ifdef USE_ETHERNET #include <Ethernet.h> #include <SSLClient.h> #include "trust_anchors.h" // アクセスするサイトのルート証明書情報 #endif // グローバル変数 time_t now; #ifdef USE_WIFICLIENTSECURE WiFiClientSecure client; #endif #ifdef USE_SSLClient WiFiClient wifi_client; SSLClient client(wifi_client, TAs, (size_t)TAs_NUM, 2); #endif #ifdef USE_ETHERNET EthernetClient ethernet_client; SSLClient client(ethernet_client, TAs, (size_t)TAs_NUM, 2); #endif // LINEへ送信 void send2Line() { String message = "message="; message += String(now); message += "秒"; #ifdef USE_WIFICLIENTSECURE client.setInsecure(); // 証明書の検証をスキップする #endif client.connect("notify-api.line.me", 443); client.println("POST /api/notify HTTP/1.0"); client.println("Authorization: Bearer " LINE_TOKEN); client.println("Content-Type: application/x-www-form-urlencoded"); client.print("Content-Length: "); client.print(strlen(message.c_str())); client.print("\r\n\r\n"); client.print(message.c_str()); while (!client.available()) { delay(10); } Serial.println(String("レスポンスコード(LINE) :") + client.readStringUntil('\n')); client.stop(); } // Machinistへ送信 void send2Machinist() { String message = "{\"agent_id\": \"" MACHINIST_ID "\","; message += "\"metrics\": ["; message += "{\"name\": \"起動時間\","; message += "\"data_point\": {"; message += "\"value\": " + String(now); message += "}}]}"; #ifdef USE_WIFICLIENTSECURE client.setInsecure(); // 証明書の検証をスキップする #endif client.connect("gw.machinist.iij.jp", 443); client.println("POST /endpoint HTTP/1.1"); client.println("Host: gw.machinist.iij.jp"); client.println("Authorization: Bearer " MACHINIST_KEY); client.println("Content-Type: application/json"); client.print("Content-Length: "); client.print(strlen(message.c_str())); client.print("\r\n\r\n"); client.print(message.c_str()); while (!client.available()) { delay(10); } Serial.println(String("レスポンスコード(Machinist):") + client.readStringUntil('\n')); client.stop(); } void setup() { Serial.begin(115200); #ifdef USE_ETHERNET Ethernet.init(26); // GPIO26はW5500のCS(SPI) byte mac[6]; esp_read_mac(mac, ESP_MAC_ETH); // ESP32のイーサネットMACアドレスを取得 Ethernet.begin(mac); // 取得したMACアドレスで初期化 Serial.println(Ethernet.localIP()); #else WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("Connecting"); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(1000); } Serial.println("Connected"); Serial.println(WiFi.localIP()); #endif } void loop() { now = time(nullptr); // 起動してからの時間を取得 Serial.println("起動時間:" + String(now)); send2Line(); // LINEへ送信 send2Machinist(); // Machinistへ送信 delay(60000); }
trust_anchors.h
#ifndef _CERTIFICATES_H_ #define _CERTIFICATES_H_ #ifdef __cplusplus extern "C" { #endif /* This file is auto-generated by the pycert_bearssl tool. Do not change it manually. * Certificates are BearSSL br_x509_trust_anchor format. Included certs: * * Index: 0 * Label: GlobalSign * Subject: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R3 * Domain(s): notify-api.line.me, gw.machinist.iij.jp */ #define TAs_NUM 1 static const unsigned char TA_DN0[] = { 0x30, 0x4c, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x17, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x52, 0x33, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x69, 0x67, 0x6e, }; static const unsigned char TA_RSA_N0[] = { 0xcc, 0x25, 0x76, 0x90, 0x79, 0x06, 0x78, 0x22, 0x16, 0xf5, 0xc0, 0x83, 0xb6, 0x84, 0xca, 0x28, 0x9e, 0xfd, 0x05, 0x76, 0x11, 0xc5, 0xad, 0x88, 0x72, 0xfc, 0x46, 0x02, 0x43, 0xc7, 0xb2, 0x8a, 0x9d, 0x04, 0x5f, 0x24, 0xcb, 0x2e, 0x4b, 0xe1, 0x60, 0x82, 0x46, 0xe1, 0x52, 0xab, 0x0c, 0x81, 0x47, 0x70, 0x6c, 0xdd, 0x64, 0xd1, 0xeb, 0xf5, 0x2c, 0xa3, 0x0f, 0x82, 0x3d, 0x0c, 0x2b, 0xae, 0x97, 0xd7, 0xb6, 0x14, 0x86, 0x10, 0x79, 0xbb, 0x3b, 0x13, 0x80, 0x77, 0x8c, 0x08, 0xe1, 0x49, 0xd2, 0x6a, 0x62, 0x2f, 0x1f, 0x5e, 0xfa, 0x96, 0x68, 0xdf, 0x89, 0x27, 0x95, 0x38, 0x9f, 0x06, 0xd7, 0x3e, 0xc9, 0xcb, 0x26, 0x59, 0x0d, 0x73, 0xde, 0xb0, 0xc8, 0xe9, 0x26, 0x0e, 0x83, 0x15, 0xc6, 0xef, 0x5b, 0x8b, 0xd2, 0x04, 0x60, 0xca, 0x49, 0xa6, 0x28, 0xf6, 0x69, 0x3b, 0xf6, 0xcb, 0xc8, 0x28, 0x91, 0xe5, 0x9d, 0x8a, 0x61, 0x57, 0x37, 0xac, 0x74, 0x14, 0xdc, 0x74, 0xe0, 0x3a, 0xee, 0x72, 0x2f, 0x2e, 0x9c, 0xfb, 0xd0, 0xbb, 0xbf, 0xf5, 0x3d, 0x00, 0xe1, 0x06, 0x33, 0xe8, 0x82, 0x2b, 0xae, 0x53, 0xa6, 0x3a, 0x16, 0x73, 0x8c, 0xdd, 0x41, 0x0e, 0x20, 0x3a, 0xc0, 0xb4, 0xa7, 0xa1, 0xe9, 0xb2, 0x4f, 0x90, 0x2e, 0x32, 0x60, 0xe9, 0x57, 0xcb, 0xb9, 0x04, 0x92, 0x68, 0x68, 0xe5, 0x38, 0x26, 0x60, 0x75, 0xb2, 0x9f, 0x77, 0xff, 0x91, 0x14, 0xef, 0xae, 0x20, 0x49, 0xfc, 0xad, 0x40, 0x15, 0x48, 0xd1, 0x02, 0x31, 0x61, 0x19, 0x5e, 0xb8, 0x97, 0xef, 0xad, 0x77, 0xb7, 0x64, 0x9a, 0x7a, 0xbf, 0x5f, 0xc1, 0x13, 0xef, 0x9b, 0x62, 0xfb, 0x0d, 0x6c, 0xe0, 0x54, 0x69, 0x16, 0xa9, 0x03, 0xda, 0x6e, 0xe9, 0x83, 0x93, 0x71, 0x76, 0xc6, 0x69, 0x85, 0x82, 0x17, }; static const unsigned char TA_RSA_E0[] = { 0x01, 0x00, 0x01, }; static const br_x509_trust_anchor TAs[] = { { { (unsigned char *)TA_DN0, sizeof TA_DN0 }, BR_X509_TA_CA, { BR_KEYTYPE_RSA, { .rsa = { (unsigned char *)TA_RSA_N0, sizeof TA_RSA_N0, (unsigned char *)TA_RSA_E0, sizeof TA_RSA_E0, } } } }, }; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ifndef _CERTIFICATES_H_ */
LINEのアクセストークンやMachinistのキー・IDの取得方法
LINEのアクセストークンは次のサイトで発行できます。
LINE Notifyのアクセストークン発行画面
MachinistのAPIキーとエージェントIDは次のサイトでアカウント登録すると発行できます。
APIキー参照画面
エージェントID参照画面
LINEとMachinistのデータ表示画面
LINE
Machinist
※2021年8月15日追記
WiFiClientSecure用の簡単な証明書の取得方法
WiFiClientSecure用の簡単なルートCAの証明書の取得方法がありましたので紹介します。
OpenSSLを使いますので、Windowsの人は次の記事を参考にしてインストールしてください。
Macの人はXcodeのコマンドラインツールがインストールされている必要があります。
Xcodeのコマンドラインツールは次のコマンドでインストールできます。
xcode-select --install
OpenSSLがインストールできたら、次ようにのコマンドを実行します。
(LINE Notify API サーバー(notify-api.line.me)の場合の例です。)
openssl s_client -showcerts -verify 5 -connect notify-api.line.me:443 < nul
Macはターミナルで
openssl s_client -showcerts -verify 5 -connect notify-api.line.me:443 < /dev/null
コマンドを実行すると次のように表示されます。 (Windowsの場合)
C:\Users\hiro>openssl s_client -showcerts -verify 5 -connect notify-api.line.me:443 < nul verify depth is 5 CONNECTED(000001A8) depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018 verify error:num=20:unable to get local issuer certificate verify return:1 depth=0 C = JP, ST = Tokyo-to, L = Shinjuku-ku, O = LINE Corporation, CN = *.line.me verify return:1 --- Certificate chain 0 s:C = JP, ST = Tokyo-to, L = Shinjuku-ku, O = LINE Corporation, CN = *.line.me i:C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018 -----BEGIN CERTIFICATE----- MIIGvTCCBaWgAwIBAgIMA5+Eduqn8JC9rUTPMA0GCSqGSIb3DQEBCwUAMFAxCzAJ BgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSYwJAYDVQQDEx1H bG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODAeFw0yMDA2MTcwNjAxNThaFw0y MjA5MDUxMjAwMDBaMGUxCzAJBgNVBAYTAkpQMREwDwYDVQQIEwhUb2t5by10bzEU MBIGA1UEBxMLU2hpbmp1a3Uta3UxGTAXBgNVBAoTEExJTkUgQ29ycG9yYXRpb24x EjAQBgNVBAMMCSoubGluZS5tZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMLkCXzXU8mAQajoVb8J80eYBE/qejymyJW2jqEunJIKakFt/fX4mqILUHsi 1auGnoZxXu5tJCfYTbfchibZZ/PiLqSRldJURgIXxub3njrpIcplAc26P1n4y62q A38XeKiIF80fTols1LNBNXhV2cKj1lRv2SwUTXZcke3noWye1oZ47QFtEuAzEFkp F9k9r2YdEqjWwuLBicrQEXVbrsRQer8YVJFvt3tpfeWSgQIOB35WReZi1M876+Yq GHBAW0/ty1Bjg+yR9hNSdrcbzOnzhnsBWantZishoJp/P5o+WhsYn8z1Oxgs7KwW Htuf59nbQgMkdAwjxugem5b2h48CAwEAAaOCA4AwggN8MA4GA1UdDwEB/wQEAwIF oDCBjgYIKwYBBQUHAQEEgYEwfzBEBggrBgEFBQcwAoY4aHR0cDovL3NlY3VyZS5n bG9iYWxzaWduLmNvbS9jYWNlcnQvZ3Nyc2FvdnNzbGNhMjAxOC5jcnQwNwYIKwYB BQUHMAGGK2h0dHA6Ly9vY3NwLmdsb2JhbHNpZ24uY29tL2dzcnNhb3Zzc2xjYTIw MTgwVgYDVR0gBE8wTTBBBgkrBgEEAaAyARQwNDAyBggrBgEFBQcCARYmaHR0cHM6 Ly93d3cuZ2xvYmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wCAYGZ4EMAQICMAkGA1Ud EwQCMAAwHQYDVR0RBBYwFIIJKi5saW5lLm1lggdsaW5lLm1lMB0GA1UdJQQWMBQG CCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBT473/yzXhnqN5vjySNiPGH AwKz6zAdBgNVHQ4EFgQUlMcjP5HQIbB0fruuvxoWlNUpg6QwggH2BgorBgEEAdZ5 AgQCBIIB5gSCAeIB4AB2ACJFRQdZVSRWlj+hL/H3bYbgIyZjrcBLf13Gg1xu4g8C AAABcsDevRsAAAQDAEcwRQIgKO4iNHwKctJ6i23CcusiS/eRybD7OgmyK6DtVJkZ nskCIQDMzwX1NU3ySt2E7a3dq6tCbgBzSGpHd56300ntq06/6QB2ACl5vvCeOTkh 8FZzn2Old+W+V32cYAr4+U1dJlwlXceEAAABcsDevcQAAAQDAEcwRQIhAONwL/C8 /sz+UxaLfwfyt+RuQNpK5TO/opHyPK2WcPIkAiAVTLmQL0LT0vIyUX0sJjPZjJ22 l3aC6FG6x803fHxQ/wB3AFWB1MIWkDYBSuoLm1c8U/DA5Dh4cCUIFy+jqh0HE9MM AAABcsDevckAAAQDAEgwRgIhANwqyszHCK1h0Y19oKD8coAROyUkVm/fcKuDqQqq 5dGJAiEA6MlqAolv+RNuiRhVBA0LNrtHE5HAdHwkRqwecNxirFgAdQBRo7D1/QF5 nFZtuDd4jwykeswbJ8v3nohCmg3+1IsF5QAAAXLA3r3dAAAEAwBGMEQCIGaE5uuM 9iv0U+i7S5+V+Hum1bMquroZ3T427DAJsi5MAiBEXZxZjFab994Ca4xhyqYKEvKP cHnXBjNqpBdCgpQB8zANBgkqhkiG9w0BAQsFAAOCAQEAfyFH/m+uOMS6zOMp8iag JTMq6d4UtFMasAEHFbbtyUS8u59gcrsDEPDRfcJbVNDPe+knIc7H8FjTrVVdWz17 Ii+ZaA5R5QWdABfejl82n8qGYuTrJk5UuZN6FTSTsoDbMxBZzcBED+ghD2vB2G6G w32Ltwail16LsDWNnwLAvd5idS2svU8BlA+O0rhBvIsBX7kFuP4TJbZ3yGjPAYXk ztj5SGLUenuTj0Yy5CWa6U67Er53x98ezOKkzaO9C0sAiv1M9ux8yK/zA1ggUpSl 7WmRjBf1LoGWFHB66olsSxYd0YwZcBgRTyzmG2S+6zURZPIipFy5OqyOaiAEtWYm wQ== -----END CERTIFICATE----- 1 s:C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018 i:OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign -----BEGIN CERTIFICATE----- MIIETjCCAzagAwIBAgINAe5fIh38YjvUMzqFVzANBgkqhkiG9w0BAQsFADBMMSAw HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yODEx MjEwMDAwMDBaMFAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52 LXNhMSYwJAYDVQQDEx1HbG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdaydUMGCEAI9WXD+uu3Vxoa2uP UGATeoHLl+6OimGUSyZ59gSnKvuk2la77qCk8HuKf1UfR5NhDW5xUTolJAgvjOH3 idaSz6+zpz8w7bXfIa7+9UQX/dhj2S/TgVprX9NHsKzyqzskeU8fxy7quRU6fBhM abO1IFkJXinDY+YuRluqlJBJDrnw9UqhCS98NE3QvADFBlV5Bs6i0BDxSEPouVq1 lVW9MdIbPYa+oewNEtssmSStR8JvA+Z6cLVwzM0nLKWMjsIYPJLJLnNvBhBWk0Cq o8VS++XFBdZpaFwGue5RieGKDkFNm5KQConpFmvv73W+eka440eKHRwup08CAwEA AaOCASkwggElMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G A1UdDgQWBBT473/yzXhnqN5vjySNiPGHAwKz6zAfBgNVHSMEGDAWgBSP8Et/qC5F JK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6 Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4Yl aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNVHSAEQDA+ MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j b20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAJmQyC1fQorUC2bbmANz EdSIhlIoU4r7rd/9c446ZwTbw1MUcBQJfMPg+NccmBqixD7b6QDjynCy8SIwIVbb 0615XoFYC20UgDX1b10d65pHBf9ZjQCxQNqQmJYaumxtf4z1s4DfjGRzNpZ5eWl0 6r/4ngGPoJVpjemEuunl1Ig423g7mNA2eymw0lIYkN5SQwCuaifIFJ6GlazhgDEw fpolu4usBCOmmQDo8dIm7A9+O4orkjgTHY+GzYZSR+Y0fFukAj6KYXwidlNalFMz hriSqHKvoflShx8xpfywgVcvzfTO3PYkz6fiNJBonf6q8amaEsybwMbDqKWwIX7e SPY= -----END CERTIFICATE----- --- Server certificate subject=C = JP, ST = Tokyo-to, L = Shinjuku-ku, O = LINE Corporation, CN = *.line.me issuer=C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018 --- No client certificate CA names sent Peer signing digest: SHA512 Peer signature type: RSA Server Temp Key: ECDH, P-256, 256 bits --- SSL handshake has read 3333 bytes and written 446 bytes Verification error: unable to get local issuer certificate --- New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES256-GCM-SHA384 Session-ID: A895A59CAA3A3FC4039ACE2C76EC64B771C845A6531812B27027327B85719FC1 Session-ID-ctx: Master-Key: EA0D759B060AD0D567AB0BA115AE5230F9B02E13478044070FD32D101DEC981AC11E37547BE9E00E8A343A6CA96EA780 PSK identity: None PSK identity hint: None SRP username: None Start Time: 1628990980 Timeout : 7200 (sec) Verify return code: 20 (unable to get local issuer certificate) Extended master secret: no --- DONE
後に表示された「-----BEGIN CERTIFICATE-----」から「-----END CERTIFICATE-----」がnotify-api.line.meのルートCAの証明書(GlobalSign Root CA)です。
プログラム例
WiFiClientSecureと証明書の扱い方が同じで、WiFiClientSecureよりも簡単にメッセージを送ることができるHTTPClinetを使った例です。
WiFiClinetSecureを使う場合は
client.setInsecure(); // 証明書の検証をスキップする
を次のようにします。
client.setCACert(line_root_ca); // ルートCAの証明書をセット
プログラム例
#include <httpclient.h> // ESP32用HTTPクライアントライブラリ #define WIFI_SSID "2.4GHzのSSID" #define WIFI_PASS "2.4GHzのSSIDのパスワード" #define LINE_TOKEN "LINE Notifyのアクセストークン" // LINE Notify API サーバーのルートCA(GlobalSign Root CA)の証明書 const char* line_root_ca = \ "-----BEGIN CERTIFICATE-----\n" "MIIETjCCAzagAwIBAgINAe5fIh38YjvUMzqFVzANBgkqhkiG9w0BAQsFADBMMSAw" "HgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFs" "U2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xODExMjEwMDAwMDBaFw0yODEx" "MjEwMDAwMDBaMFAxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52" "LXNhMSYwJAYDVQQDEx1HbG9iYWxTaWduIFJTQSBPViBTU0wgQ0EgMjAxODCCASIw" "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKdaydUMGCEAI9WXD+uu3Vxoa2uP" "UGATeoHLl+6OimGUSyZ59gSnKvuk2la77qCk8HuKf1UfR5NhDW5xUTolJAgvjOH3" "idaSz6+zpz8w7bXfIa7+9UQX/dhj2S/TgVprX9NHsKzyqzskeU8fxy7quRU6fBhM" "abO1IFkJXinDY+YuRluqlJBJDrnw9UqhCS98NE3QvADFBlV5Bs6i0BDxSEPouVq1" "lVW9MdIbPYa+oewNEtssmSStR8JvA+Z6cLVwzM0nLKWMjsIYPJLJLnNvBhBWk0Cq" "o8VS++XFBdZpaFwGue5RieGKDkFNm5KQConpFmvv73W+eka440eKHRwup08CAwEA" "AaOCASkwggElMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G" "A1UdDgQWBBT473/yzXhnqN5vjySNiPGHAwKz6zAfBgNVHSMEGDAWgBSP8Et/qC5F" "JK5NUPpjmove4t0bvDA+BggrBgEFBQcBAQQyMDAwLgYIKwYBBQUHMAGGImh0dHA6" "Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjMwNgYDVR0fBC8wLTAroCmgJ4Yl" "aHR0cDovL2NybC5nbG9iYWxzaWduLmNvbS9yb290LXIzLmNybDBHBgNVHSAEQDA+" "MDwGBFUdIAAwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xvYmFsc2lnbi5j" "b20vcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBAJmQyC1fQorUC2bbmANz" "EdSIhlIoU4r7rd/9c446ZwTbw1MUcBQJfMPg+NccmBqixD7b6QDjynCy8SIwIVbb" "0615XoFYC20UgDX1b10d65pHBf9ZjQCxQNqQmJYaumxtf4z1s4DfjGRzNpZ5eWl0" "6r/4ngGPoJVpjemEuunl1Ig423g7mNA2eymw0lIYkN5SQwCuaifIFJ6GlazhgDEw" "fpolu4usBCOmmQDo8dIm7A9+O4orkjgTHY+GzYZSR+Y0fFukAj6KYXwidlNalFMz" "hriSqHKvoflShx8xpfywgVcvzfTO3PYkz6fiNJBonf6q8amaEsybwMbDqKWwIX7e" "SPY=\n" "-----END CERTIFICATE-----\n"; // LINEへ送信 void send2Line(time_t now) { // 送信するメッセージ String message = "message="; message += String(now); message += "秒"; // LINE Notify APIサーバーにメッセージを送信 HTTPClient http; http.begin("notify-api.line.me", 443, "/api/notify", line_root_ca); http.addHeader("Authorization", "Bearer " LINE_TOKEN); http.addHeader("Content-Type", "application/x-www-form-urlencoded"); int sc = http.POST(message.c_str()); http.end(); Serial.print("ステータスコード:"); Serial.println(sc); } // ネットワーク接続 void connectNetwork() { Serial.print("Connecting " WIFI_SSID); WiFi.mode(WIFI_STA); WiFi.disconnect(true); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { // WiFiが繋がるまでループ Serial.print("."); delay(1000); } Serial.println(" done."); Serial.print("IP Address: "); Serial.println(WiFi.localIP()); // IPアドレスを表示 } void setup() { Serial.begin(115200); while (!Serial); Serial.println(); connectNetwork(); // ネットワーク接続 } void loop() { time_t now = time(nullptr); // 起動してからの時間を取得 Serial.println("起動時間:" + String((int)now)); send2Line(now); // LINEへ送信 delay(60*1000); }
HTTPClientはWiFiClientSecureよりコードが短く簡単ですが、バイナリデータを送れません。