LoginSignup
13
10

More than 5 years have passed since last update.

ESP8266でEAP-TLS無線接続

Last updated at Posted at 2016-07-22

WAP PSK=Preshared key ではなく、端末をSSL証明書で認証して無線接続するお話し。カテゴリ分けすると、いわゆる WPA2 Enterprise です。

証明書

ここでは V1 の証明書で、無線基地局(AP)=認証局(CA)で構成してみた。基地局複数ある場合とか、一般的には分けたほうがいいです。

うっかり openssl デフォルトの V3 証明書の設定が使われないように、あらかじめ設定ファイル v1.conf を用意しておく。

v1.conf
[req]
distinguished_name=none

[none]

まず AP 側の鍵と証明書を作る。req -x509 -new が「鍵作成+自己署名証明書(CSRは暗黙処理)」のショートカットになっているので、これで作るのが簡単。参考

openssl req -config v1.conf -subj /C=JP/OU=Dev/CN=ap -keyout ap.key -x509 -new -nodes -out ap.crt

次に ESP8266 である無線端末(STA)側の証明書を作る。こちらは AP の証明書で署名するので CSR を作る。req -new が「鍵作成+CSR」のショートカット。

openssl req -config v1.conf -subj /C=JP/OU=DEV/CN=sta -nodes -new -keyout sta.key -out sta.csr

署名する。x509-config を取らず、すこしルールが違う。-extfile を指定すると V3 になる。-extensions を指定すると、デフォルトを上書きする。ということで、-extensions に存在しない値を指定するのみ、で V1 にできる。

echo 10 > ap.srl
openssl x509 -CA ap.crt -CAkey ap.key -req -in sta.csr -out sta.crt -extensions none

これで ap.crt, ap.key と sta.crt, sta.key が揃った。

hostapd

hostapd 組み込みの eap_server 機能を利用すると簡単。

ap.conf
driver=nl80211
interface=wlan0
ssid=esptls
channel=1
wpa=2
wpa_key_mgmt=WPA-EAP
ieee8021x=1
eapol_version=2
eap_server=1
ca_cert=ap.crt
server_cert=ap.crt
private_key=ap.key
eap_user_file=ap.user

ap.user のファイルはこんな感じで用意する。どんなユーザでも EAP-TLS でネゴシエーションされるという意味。

ap.user
* TLS

以上二つのファイルを用意して次のように起動する。

hostapd ap.conf

ところで例えば ubuntu のデフォルトの状態だと、NetworkManager が wifi のインターフェースを掴んで、うまく動作させられなかったりする。そんなときは nmcli を使ってこんな感じに開放する。

nmcli radio wifi off
# nmcli が wifi off するときに同時に rfkill するので、それを打ち消す
rfkill off 0

ESP8266

ESP8266/Arduino な Arduino スケッチ環境で次のように作る。参考

いくつかポイントがある。

  • extern "C" を使う。さもないと linker で問題が出る。
  • wifi_station_set_cert_key の引数はファイルの中身そのもの。最後の NULL termination を含めた長さを引数に渡すこと。重要。ここでは文字列を渡しているけれど、多くの場合は、ファイルから読みだすことを想定しているんだと思う。
  • 証明書の鍵のパスワードを設定できそうな引数になっているけれど、未実装で NULL, 0 を渡せとドキュメントに書かれている。
sketch.ino
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
extern "C" { // We're calling ESP8266 SDK "C" interface
#include <user_interface.h>
}

const char tls_cert[] = "-----BEGIN CERTIFICATE-----\n"
"MIICxTCCAa0CAREwDQYJKoZIhvcNAQELBQAwKDELMAkGA1UEBhMCSlAxDDAKBgNV\n"
"BAsMA0RldjELMAkGA1UEAwwCYXAwHhcNMTYwNzIyMTcyOTU5WhcNMTYwODIxMTcy\n"
"OTU5WjApMQswCQYDVQQGEwJKUDEMMAoGA1UECwwDREVWMQwwCgYDVQQDDANzdGEw\n"
"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhBuYj3mtHaJSc0UIk0xZq\n"
"12MZo2fVFD7pfsg1w4HLo2+aDcF3zgxYy8+QZPR9rGmy6Tqj/T/e0NNHMTJgOoEk\n"
"O6OxpwkjcTp6+VGjWt0IkJsO/Ikn5s0/1nz5Xs0Tudy3jyLzfzeHqFFHidxgd7oH\n"
"D8/OTQ8dQekZwMCeITmUY5xa6D4qdRSuOMjuF7FFTqfZvW/rW8eMIatW0VowuXHW\n"
"zXqVwi8CsdA7g7nwMWYPZZOAF1iDzEJs3O6eYhirk3+1wQon4DkL141ZxIi6JHl1\n"
"qzXvtVzSMHAE7QLH2rKBy6oNjUuiLjwOBQaAE8g140XgefB91r2M+akNEXTZ4sGr\n"
"AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGKeE0+5xnftMr5AXSIN3AtVeChBhA30\n"
"vXtvL209MxmsmUFqS1jT0mIVshPoZt1Irevdu6S3FBh4F9OCN9N3YtVh8S+fyzLx\n"
"WJI2eVONDiwbdU1cOEeG7tGx+igURqCEBtbYcE3gZZ80ndocLtXgkwWkyetmm7uD\n"
"9ut3t1AnXygwxHK/jfG6eCfwRUMSN5EWxaSs1VpnJ0qt6v0AfaNk9oUZUUtLTP6C\n"
"LmFI/2/hr3oPvdMFDoSxeK9FGv14LqHEfwuw2Mb34YvGBU3ptf1V5bs89tGJcF5w\n"
"RfJXAVqXplA8yzUyDpk4iIVdD2yO+Z/6LXbbR1g0Peb9VUgj6dHdQEQ=\n"
"-----END CERTIFICATE-----\n";

const char tls_key[] = "-----BEGIN PRIVATE KEY-----\n"
"MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDhBuYj3mtHaJSc\n"
"0UIk0xZq12MZo2fVFD7pfsg1w4HLo2+aDcF3zgxYy8+QZPR9rGmy6Tqj/T/e0NNH\n"
"MTJgOoEkO6OxpwkjcTp6+VGjWt0IkJsO/Ikn5s0/1nz5Xs0Tudy3jyLzfzeHqFFH\n"
"idxgd7oHD8/OTQ8dQekZwMCeITmUY5xa6D4qdRSuOMjuF7FFTqfZvW/rW8eMIatW\n"
"0VowuXHWzXqVwi8CsdA7g7nwMWYPZZOAF1iDzEJs3O6eYhirk3+1wQon4DkL141Z\n"
"xIi6JHl1qzXvtVzSMHAE7QLH2rKBy6oNjUuiLjwOBQaAE8g140XgefB91r2M+akN\n"
"EXTZ4sGrAgMBAAECggEBAJjz2YZT7lNxUGJvEih5mmkw0dlhang49LI9TNTOePDz\n"
"vC3YX8KROW85yXH6TP0HLik/wm4o+zr2ckWXuQgTfCgmqZNdWCbRFdD0mnsQjeD+\n"
"eYbsPEX06VoU7omJ2Jcp5E6YakdcF2CMFgMsP7EKcFXQd41gb3+Rh2HL1KEnMD4d\n"
"WDZyOxS+0pUXp7LwUTHAaLelqWVH4yHukG9B1xTkApBItVjfSYHwCzQLY3zJgwsc\n"
"3iqiN1Uqqt3X7jxjpcyJjLbLpC5QXVB3f7ExUyMw4rDIE3NiJp4Pczx7rhotUR6J\n"
"KZ2LJDoq5LGeFff7cqMnQaXdNKFYCEYA0P602Dlx58ECgYEA/Mv9xNgOcfVDFdwd\n"
"A4wEfZSRxXp5aWbty+x91/ap6mn5gKmX5DzuNGch3nDwjELCePJ2zL/OdCcNhGOy\n"
"61Ok8a+1oe4heZie5AtyAD+5c7IQw+TtSNmfWGUBJDv8ixSUFEvqgmxj7UirfYZW\n"
"kqnLfb80Qz3XLGf/ugSTK6GCyBsCgYEA4+DUSD/folIZ175LEKZlctRwFP507Ala\n"
"5FAMySl1Gi/bohnt+3Vs6ph/GaSIg+Q+6r39loQKT40iwW4tSQrV6qBtJ99VDbe4\n"
"JiKswc5VbSzV5rfYVITBZ41yFv4wFd1zrGItEYVshn1WRfGU904helV7up0yfIZD\n"
"t8BEgGxHpbECgYEAxkEg+vBKm9qySwF+C5sSpn4OuGXts9jSI3yL0QQUi8+iqeHX\n"
"SlryoUxEhpPiQs3UgE//FWJTgkpiUnJyDhZiJF0dwCnmPNuRuNy1Ajb3tSFv/oGa\n"
"CekKC6Pi+kzFKTnxS92hw7lHwP6d52qkmI7rFOoQDbABAUVqi7MszCn1TAMCgYEA\n"
"kmAL2/DzhL+6C+QXMbXAupcM+99LWYbU1I06+UhhCRYuvZxsSrbt5G9aTS1r51SI\n"
"uZ6assFUIi9lYNyVyDJmoFS2aQNDDhGx/wUM9VzFcOB48b+r/PZdiVfJLk3Os2zR\n"
"bayOiI+s22LNNRZt+sE8LemVFZT+JhDUlMay+c8T4rECgYEApxWKko+0nHGgdzzn\n"
"167JRzKCFFfegmlEbNaDJhwfQLjoTo2wCeBkFmERoeaSeXIHjvhA3imC7azVXlTM\n"
"paRvvYNtWpvg9hIBCpgCioJbkUQ+2tOAP5gLuQHo758D+pSArl8qlh9oLkbeI4tr\n"
"np6r/Ydn1mho+8AtCSfxK6mlrvU=\n"
"-----END PRIVATE KEY-----\n";

void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println("hello");
  int w = wifi_station_set_cert_key((uint8*)tls_cert, strlen(tls_cert)+1, (uint8*)tls_key, strlen(tls_key)+1, NULL, 0);
  Serial.printf("cert %d\n", w);
  WiFi.mode(WIFI_STA);
  Serial.println("before connect");
  int st = WiFi.begin("eaptls", "unused_dummy");
  Serial.printf("after connect %d\n", st);
}

void loop() {
}

今の ESP8266/Arduino は espressif NON-OS SDK 1.5.3 を使っている。NONOS SDK の最新版は現時点で 2.0 になっていて、EAP-PEAP のサポートが追加されたりしているので、きっと 1.5 よりも安定している。wpa2_enterprise.h として分離されていたりする。ESP8266/Arduino の対応が待ち遠しい。

接続

hostapd 側のログに、こんな感じで出てきたら接続成功。

EAP method=13 が EAP-TLS。method=1 は Identity。method=1の後にmethod=13が出ていればokで、そのあとに starting accounting session が出ていれば接続確立。

wlan0: STA 18:fe:34:ee:84:58 IEEE 802.11: authenticated
wlan0: STA 18:fe:34:ee:84:58 IEEE 802.11: associated (aid 1)
wlan0: STA 18:fe:34:ee:84:58 IEEE 802.11: authenticated
wlan0: STA 18:fe:34:ee:84:58 IEEE 802.11: associated (aid 1)
wlan0: CTRL-EVENT-EAP-STARTED 18:fe:34:ee:84:58
wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
wlan0: CTRL-EVENT-EAP-STARTED 18:fe:34:ee:84:58
wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=1
wlan0: CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=13
handle_beacon - too short payload (len=28)
wlan0: CTRL-EVENT-EAP-SUCCESS 18:fe:34:ee:84:58
wlan0: STA 18:fe:34:ee:84:58 WPA: pairwise key handshake completed (RSN)
wlan0: AP-STA-CONNECTED 18:fe:34:ee:84:58
wlan0: STA 18:fe:34:ee:84:58 RADIUS: starting accounting session 57923653-00000000
wlan0: STA 18:fe:34:ee:84:58 IEEE 802.1X: authenticated - EAP type: 0 (unknown)
handle_beacon - too short payload (len=25)
handle_beacon - too short payload (len=32)

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10