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を使用して証明書のデータを更新。(長くなったのでこちら)
フィンガープリントだけで接続
フィンガープリント設定すればとりあえずつながる。
const char fingerprint_www_example_org [] PROGMEM = "4d:a2:5a:6d:5e:f6:2c:5f:95:c7:bd:0a:73:ea:3c:17:7b:36:99:9d";
#define FINGERPRINT fingerprint_www_example_org
BearSSL::WiFiClientSecure client;
client.setFingerprint(FINGERPRINT);
fetchURL(&client, SSL_host, SSL_port, path);
何もないよりましだといっている
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とのこと。
BearSSL::WiFiClientSecure client;
client.allowSelfSignedCerts();
fetchURL(&client, "self-signed.badssl.com", 443, "/");
こいつは自己署名は誰でも作れるから注意を(略
It is also possible to accept *any* self-signed certificate. This is
absolutely insecure as anyone can make a self-signed certificate.
ハードコード公開鍵で接続
const char pubkey_www_example_org [] PROGMEM = R"PUBKEY(
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhoUPuw75yl/Z9eAKMiwz(略)
#define PUBKEY pubkey_www_example_org
BearSSL::WiFiClientSecure client;
BearSSL::PublicKey key(PUBKEY);
client.setKnownKey(&key);
fetchURL(&client, SSL_host, SSL_port, path);
公開鍵をハードコードしておいてそいつを使って(通常の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をハードコード方式(多分一番固い)
const char pubkey_www_example_org [] PROGMEM = R"PUBKEY(
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhoUPuw75yl/Z9eAKMiwz
#define CERT cert_DigiCert_Global_G2_TLS_RSA_SHA256_2020_CA1
BearSSL::X509List cert(CERT);
client.setTrustAnchors(&cert);
setClock();// 有効期間確認用に時刻設定(詳細はソース確認)
fetchURL(&client, SSL_host, SSL_port, path);
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.
//#define CERT cert_DigiCert_Global_G2_TLS_RSA_SHA256_2020_CA1
#define CERT cert_DigiCert_Global_Root_G2
上のように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ハッシュ
自分で指定