espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.41k stars 7.25k forks source link

[TW#12246] Not able to make wpa2-entrprise example work #248

Closed helmut-s closed 7 years ago

helmut-s commented 7 years ago

I just slightly altered the wpa2_enterprise_main (set all required values and removed the whole certificate stuff (should be optional)) The wifi in my company I am trying to connect uses PEAP-MSCHAPv2. But whatever I try the outcome is always the same (at least the last line): I (668) wpa: WPA2 ENTERPRISE VERSION: [v2.0] enable I (668) wifi: rx_ba=1 tx_ba=1 I (668) wifi: mode : sta (24:0a:c4:00:a3:2a) I (798) wifi: n:1 0, o:1 0, ap:255 255, sta:1 0, prof:1 I (1448) wifi: state: init -> auth (b0) I (2448) wifi: state: auth -> init (2) I (2568) wifi: n:1 0, o:1 0, ap:255 255, sta:1 0, prof:1 I (2568) wifi: state: init -> auth (b0) I (2578) wifi: state: auth -> assoc (0) I (2588) wifi: state: assoc -> run (10) I (2588) wpa: wpa2_task prio:24, stack:6144 I (8588) wpa: >>>>>wpa2 FIALED (not a typo - at least not mine)

Is there anything I can do to figure out what is going on (more verbose logging, ....)

TimXia commented 7 years ago

Sorry, the log in wpa2-enterprise module is closed now. It may be opened in the next version. You can try to capture EAP packets to see what happened using WiredSharke or OmniPeek during wpa2-enterprise connection. Or you can check the log on the Radius server. Maybe your configuration of ESP32 does not meet that of your Radius server (eg. Identity, Username or Password).

helmut-s commented 7 years ago

I managed to make it work! If trust the CA of our certificate by (creating the appropriate pem file) and calling esp_wifi_sta_wpa2_ent_set_ca_cert it works. So obviously this call is not optional. Omitting it does NOT disable certificate verification (what I assumed) it just fails all the time. Can anybody confirm that? How can I disable the certificate check? Always providing the correct CA cert is not an option for me!

joostd commented 7 years ago

Did you try esp_wifi_sta_wpa2_ent_clear_ca_cert() to remove a previously set ca certificate?

helmut-s commented 7 years ago

yes - tried that!

helmut-s commented 7 years ago

also tried "make erase_flash" (without success)

TimXia commented 7 years ago

@helmut-s @joostd It is optional to verify CA cert in esp32. Maybe the configuration of your Radius server requires esp32 to verify CA cert. Please check it.

joostd commented 7 years ago

@helmut-s Why is always providing the correct CA cert not an option? I would say it is not an option not to! What is the point of using WPA2-Enterprise when you cannot keep your credentials secret?

helmut-s commented 7 years ago

I do not think that RADIUS server somehow recognizes if the client verifies the certificate or not. This was one reason I tried the verification as our logon server did not show any signs of me trying to authenticate. My guess is it fails already at the stage of establishing the secure session

TimXia commented 7 years ago

I think that if Radius server provides server cert but client has no CA cert to verify it, the authentication fails.

helmut-s commented 7 years ago

@joostd - You mean if you connect with your handy into an enterprise secured WIFI you somehow upload a pem file to your handy and specify it there? Clicking 'yes' and confirming the certificate is fine but needing to provide a pem file does not sound too convenient. I would not even know how to get it (if not provided by someone else)

helmut-s commented 7 years ago

@TimXia - I think the RADIUS server should not have anything to do with it. It is something between the Authenticator and the client. Anyhow, if the client verifies the cert or not is nothing that the server side would (or could) recognize Correction: Actually the Authenticator is the one which is not involved. It is only passing things through. The handshake is happening between the client and the radius server

joostd commented 7 years ago

@helmut-s No need to upload anything to end-user devices. The RADIUS server sends the certificate to your device. You are prompted to accept it. See for instance this iOS screenshot.

When using a public CA such as Digicert or Comodo, the CA certificate is validated by the root CA certificate, which is already present on your device. For example, see the list of preloaded CA certificates for iOS.

Such a list is not present on the esp32, so you need to specify it in firmware. That's basically what esp_wifi_sta_wpa2_ent_set_ca_cert does.

helmut-s commented 7 years ago

@joostd - Thanx! I am clear about that. But being able to provide the users of a device (where the esp32 is built in) the same user experience as your screenshot shows I would need some kind of callback functions which provides the server certificate that I can (let the user) accept or not. Just being able to use a list of predefined CAs makes it very cumbersome to connect. Anyhow, as the esp_wifi_sta_wpa2_ent_set_ca_cert function is considered optional I do not think it was intended to force the user to specify trusted CAs, or am I wrong here?

joostd commented 7 years ago

The iOS user experience is not an option for an embedded device. Hence the discussion in #247 where you specify what server certificates to accept using both the CA root certificate and the server Common Name in firmware, so that no user interaction is required.

helmut-s commented 7 years ago

@ joostd - I think it should be an option. The embedded device could have a screen and some methods for user input or it could be connected to another device (handy) via Bluetooth or the AP mode, ....... What I did not get so far: Do you know that it behaves like intended by espressif architects or is it just your opinion how it should behave? Whatever your answer is - why is it considered optional then?

negativekelvin commented 7 years ago

It makes sense that no certificate should mean disable certificate verification because I don't think you can prevent the server from sending a certificate under these protocol options.

helmut-s commented 7 years ago

@negativekelvin - Could not agree more!

I am new here. So how is it working? It's called an issue - does anybody read this who is able to fix bugs. It's obviously in the closed source section...

TimXia commented 7 years ago

@helmut-s In esp32, if the CA cert is not installed, it will not verify the cert sent by Radius server. Otherwise, it will verify the name and time of the cert sent by Radius server. In our test, installing CA cert or not is both OK.

helmut-s commented 7 years ago

@TimXia - Thank you for your reply. Unfortunately my tests show exactly the opposite. If I just remove the one line containing esp_wifi_sta_wpa2_ent_set_ca_cert it stops working. I think the TLS tunnel establishment between the RADIUS server and the esp is equal what is happening in a browser (Client hello, Server Hello, ....) There is nothing the server requests from the client when it comes to trusting its certificate. If the client trusts it responds to the server hello, if not it terminates the TLS tunnel establishment. It is just a decision from the client. There is no setting on the server side which could influence that. E.g. if I use my handy I get a certificate message where it tells me who issued the server certificate and if I want to trust it. If I click yes, I can establish the wifi connection. Installing this root CAs is just about not needing to present the user these dialogs but immediately trust the cert. I can absolutely not think of any other explanation to the observed behavior other than that the esp2 does not trust the server certificate (despite no CA cert is provided). How can we proceed? Is there anything I could provide or try to help troubleshooting this issue?

helmut-s commented 7 years ago

@TimXia - One thing that could make some difference (I could still not explain what exactly is happening) is when you maybe use a self signed certificate for your tests. I am using a publicly valid one.

helmut-s commented 7 years ago

What is also worth to mention is that it is only working if I specify the certificate of the direct issuer of the actual server certificate, not any other CA up in the certification path

TimXia commented 7 years ago

@helmut-s Yes. I used a self signed cert in my test. What's the difference between self signed cert and publicly valid one?

helmut-s commented 7 years ago

A self signed certificate actually is not signed by a CA (does not have certification path). So it is kind of signed by itself. In my tests I added the certificate of the CA (esp_wifi_sta_wpa2_ent_set_ca_cert) which issued the actual server certificate. You must have specified the server certificate itself. As mentioned, I am not clear what is going on/wrong, but obviously there must be a difference which makes our 2 tests behave differently - and this at least is a trace...

helmut-s commented 7 years ago

@ TimXia - BTW - this is a good step by step instruction on how to build your own certificate chain with openssl: https://jamielinux.com/docs/openssl-certificate-authority/index.html

helmut-s commented 7 years ago

@TimXia I setup a test environment now to troubleshoot the certificate issue but unfortunately now I do not even get to the TLS tunnel setup section. I am using a LinksysWAP300N against a freeradius server on a raspberry pi. Using my handy the authentication works fine. Using esp32 it failes. I enabled all debug log settings on freeradius and it seems that the client sends some incorrect request:

log file: ....... Debug: [eap] Request found, released from the list Debug: [eap] EAP NAK Debug: [eap] NAK asked for bad type 0 Debug: [eap] Failed in EAP select Debug: ++[eap] returns invalid Debug: Failed to authenticate the user. .......

from a working login with my handy: ....... Debug: [eap] Request found, released from the list Debug: [eap] EAP NAK Debug: [eap] EAP-NAK asked for EAP-Type/peap Debug: [eap] processing type tls Debug: [tls] Initiate .......

TimXia commented 7 years ago

It seems that esp32 replies an EAP packet with bad EAP type. As I know, many handy replies EAP type according to the user's input. But in esp32, the EAP type depends on the received EAP request packet. Maybe the EAP request packet is somewhere different. Could you please capture the EAP packets using wireshark or omnipeek and upload them to github? We will analysis it asap.

helmut-s commented 7 years ago

Here we go radius_dump.zip

helmut-s commented 7 years ago

@TimXia - Specifying peap as eap type in freeradius makes it work (works around the negotiation). Unfortunately it makes my example setup work at a whole, no matter if I use a self signed or a CA signed certificate. So it will be hard to find the problem with my company network. My only hope is that is is actually a related issue (maybe even the same) affecting the inner channel and that the providing of the trusted CA works around some non working negotiation protocol...

helmut-s commented 7 years ago

@TimXia - Any update? Have you been able to analyze it?

TimXia commented 7 years ago

Sorry, I was on holiday last two weeks. According to the packets which you provided, the Radius is configured as EAP-MD5. It should be configured as EAP-PEAP.

FayeY commented 7 years ago

Hi helmut-s, is this problem still unsolved?

helmut-s commented 7 years ago

Unfortunately it is still existent. A cannot connect to our company wifi without specifying a CA (esp-idf-v2.0)and I still do not think that the wifi can enforce this somehow. I believe it has something to do with different code beeing executed in the ESP32 in case a CA is provided and obviously this code seems to work.

WGH- commented 7 years ago

I'm also having problems with

[eap] Request found, released from the list
[eap] EAP NAK
[eap] NAK asked for bad type 0
[eap] Failed in EAP select

I tried both EAP-TLS, and EAP-TTLS-MSCHAPv2.

My freeradius server is using self-signed certificate. It doesn't matter if I specify it with wifi_station_set_enterprise_ca_cert or not.

I know that wpa_supplicant is licensed under BSD, so Espressif doesn't have to open-source the code, but everything would be much simpler if you did.

WGH- commented 7 years ago

@helmut-s No need to upload anything to end-user devices. The RADIUS server sends the certificate to your device. You are prompted to accept it. See for instance this iOS screenshot.

When using a public CA such as Digicert or Comodo, the CA certificate is validated by the root CA certificate, which is already present on your device. For example, see the list of preloaded CA certificates for iOS.

Such a list is not present on the esp32, so you need to specify it in firmware. That's basically what esp_wifi_sta_wpa2_ent_set_ca_cert does.

I want to clarify this a bit.

I'm not sure about FreeRADIUS, but in general, TLS server always sends its own certificate, and it may, depending on the configuration, send entire (or even partial) certificate chain as well.

Some devices, like iOS, seem to allow you to trust a single certificate, which apparently can be self-signed. Not sure if iOS allows you to trust a not self-signed certificate.

The other option is to trust some certificate authority (e.g. the one of your organization), which issues a server certificate for a radius server. This way, radius certificate may be reissued, organization may use several radius servers with different certificates, and so on. This option seems to be more widely supported, e.g. by Android, Windows.

As of generally trusted public CAs, I honestly haven't seen a RADIUS certificate that was signed by some "trusted by default" CA (directly or indirectly). I've only seen self-signed certificates or certificates signed by some "internal" certificate authority. So in order to connect, you'll need to trust that CA manually. Moreover, it seems that supplicants (like wpa_supplicants on Linux) don't use system certificate storage (which is mainly used for HTTPS) to validate WPA Enterprise certs.

Now, let's get back to esp8266. Its supplicant seems to be based on well known wpa_supplicant. In my configuration on my Linux machine (which obviously uses wpa_supplicant), ca_cert points to self-signed certificate of the radius server. And certificate verification succeeds.

I also tried supplying some random identities, with @ sign and without. It worked anyway, so we can probably conclude that hardcoded anonymous@espressif.com identity is not the problem (at some point I thought it was).

WGH- commented 7 years ago

OK, it seems that some setup in freeradius does make a difference.

After I changed default_eap_type to tls from default md5, EAP-TLS on esp8266 suddenly started to work.

Well, I have mixed devices in my network, some use EAP-TLS, some - EAP-PEAP-MSCHAPv2 (none md5, actually), but somehow only esp8266 requires changing this

helmut-s commented 7 years ago

@WGH- I had exactly the same problems with freeradius and made it work after the change as well. Using MD5 results in a protocol error but I was told that the esp32 just does not support MD5 (fair enough). With the freeradius however it did not make a difference if I specified the CA or not - it always worked. With my company network however it does just work by providing the CA (just containing the server cert). I am still convinced that this is a problem of the esp32 implementation as it is up to the client to trust it or not and there should not be any difference from the server point of view.

dvoelkel commented 7 years ago

Is there a sample code to perform WPA2-enterprise with certificate?

joostd commented 7 years ago

Do you mean using EAP-TLS with a client certificate? The example in this repo should work: https://github.com/espressif/esp-idf/tree/master/examples/wifi/wpa2_enterprise

dvoelkel commented 7 years ago

To be honest: I'm not sure. We are using WPA-Enterprise, which means, a client has a installed certificate. to connect the pc with the network it is only necessary to tell the ssid. The password is not needed. The security is handled with the certificate. I don't know how to do this with esp32. (later with esp8266 too)

joostd commented 7 years ago

Yes, that's EAP-TLS, and it should work if you plug in your SSID, the CA certificate, your client certificate, and the corresponding private key.

For esp8266, you can find an example here: https://github.com/joostd/esp8266-eduroam/blob/master/wpa2e-v15/user_main.c (although I think that may be a bit outdated).

dvoelkel commented 7 years ago

Wow. Ok. Then I will try this way. First I seem to need the client-cert and the key. We use windows, so I have to search the certsrv for the needed files.

WGH- commented 7 years ago

Here's the code I use. The SDK version is probably ESP8266_NONOS_SDK_V2.0.0_16_08_10 (whatever it means, I use esp-open-sdk, so I don't really know all the SDK details).

I had to turn off checking of server certificate (otherwise it doesn't work). The server certificate is self-signed, FWIW.

And, as mentioned above, I also had to change default_eap_type to tls from default md5 in my freeradius config.

As you can see, the login/password part is commented out. I couldn't make it work, though, frankly, I didn't try very hard.


extern unsigned char _binary_fridge_logger_crt_start;
extern unsigned char _binary_fridge_logger_crt_end;
extern unsigned char _binary_fridge_logger_crt_size;

extern unsigned char _binary_fridge_logger_key_start;
extern unsigned char _binary_fridge_logger_key_end;
extern unsigned char _binary_fridge_logger_key_size;

extern unsigned char _binary_raspberrypi_pem_start;
extern unsigned char _binary_raspberrypi_pem_end;
extern unsigned char _binary_raspberrypi_pem_size;

void ICACHE_FLASH_ATTR my_wifi_init(void (*cb)(void))
{
    bool res;
    struct station_config stationConf;

    memset(&stationConf, 0, sizeof(struct station_config));

    strcpy(&stationConf.ssid[0], WIFI_SSID);

    wifi_set_opmode_current(STATION_MODE);

    wifi_station_set_config_current(&stationConf);
    res = wifi_station_set_wpa2_enterprise_auth(1);
    if (res) {
        os_printf("failed to enable wpa2 enterprise\n");
        return;
    }

    /*
    res = wifi_station_set_enterprise_ca_cert(
        &_binary_raspberrypi_pem_start, 
        ((size_t) &_binary_raspberrypi_pem_size)
    );
    if (res) {
        os_printf("failed to set ca cert\n");
        return;
    }
    */

    /*
    res = wifi_station_set_enterprise_username(WIFI_USERNAME, strlen(WIFI_USERNAME));
    if (res) {
        os_printf("failed to set username\n");
        return;
    }
    res = wifi_station_set_enterprise_password(WIFI_PASSWORD, strlen(WIFI_PASSWORD));
    if (res) {
        os_printf("failed to set password\n");
        return;
    }
    */

    res = wifi_station_set_enterprise_cert_key(
        &_binary_fridge_logger_crt_start,
        ((size_t) &_binary_fridge_logger_crt_size),
        &_binary_fridge_logger_key_start,
        ((size_t) &_binary_fridge_logger_key_size),
        NULL,
        0 
    );
    if (res) {
        os_printf("failed to set client certificate\n");
        return;
    }

    wifi_set_event_handler_cb(wifi_handle_event_cb);

    wifi_ready_callback = cb;

    wifi_station_connect();
}

These weird-looking extern symbols reference actual certificate/key data (in PEM encoding, that is, -----BEGIN type----- followed by base64 followed by -----END type----- followed by null byte). Object files are generated by Makefile rules like these, and then simply linked into binary like ordinary code:

fridge_logger_crt.o: fridge_logger.crt
    xtensa-lx106-elf-objcopy -I binary -O elf32-xtensa-le -B xtensa $^ $@

You don't have to do that the same way, obviously, you could simply use unsigned char cert[] = {0x2d, 0x2d, 0x2d, 0x2d, 0x2d, ....};

TimXia commented 7 years ago

@helmut-s The freeradius should set EAP type as TLS, PEAP or TTLS. ESP32 does not support any other EAP method. By the way, what is the difference of configuration between your company's radius server and the testing freeradius? Can you provide the log if you do not set CA cert into esp32 and connect to the AP?

helmut-s commented 7 years ago

Unfortunately I do not know any differences (other than it is not freeradius of course). It's set to PEAP. Are there already some logging capabilities on the client side which I could turn on, or are you talking about server side logs? (When I requested them once, IT told me that there is no evidence at all that I tried to connect)

TimXia commented 7 years ago

The server side. Please use the latest IDF code. Just fix a bug about WPA2 enterprise recently.

FayeY commented 7 years ago

Any update? Is this problem solved now?

exquisitetelescope commented 6 years ago

@FayeY Do you know if the bug with WPA2 enterprise authentication selection where previously on the ESP32 you had to define default_eap_type=peap has been fixed for the ESP8266?

mrrosen commented 6 years ago

Not to rake up old issues, but for anyone else having trouble connecting to WPA2 Enterprise (in my case with PEAP-MSCHAPv2) without setting the CA Certificate, I couldnt make it work without calling esp_wifi_sta_wpa2_ent_set_ca_cert (ie, once I added in esp_wifi_sta_wpa2_ent_set_ca_cert with the CA used in my authentication server's TLS Server Hello, it worked and wouldnt work without it). This might just be an older IDF thing as the IDF I am using is from a while ago, but still, it seems like its very easy to get the process to fail without a CA certificate. Reason seems to be that the client (ESP32) will send a TLS Alert telling the server that the server certificate was bad even if you call esp_wifi_sta_wpa2_ent_clear_ca_cert. In some cases, the server will response with an EAP Failed message, triggering a failure to connect on the ESP32 side. For a long time, we didnt have this issue until one day, it changed and we could no longer connect (I assume because our IT department updated something to do with the WPA2 Auth or RADIUS server). Just as a summary for anyone else that finds this thread....

helmut-s commented 6 years ago

I experience exactly the same behavior. I tried a lot of different ESP-IDF version in the hope that they finally fixed if (for me this is definitely a client bug, triggered by some server setting), but without any luck.