arduino-libraries / ArduinoBearSSL

Port of BearSSL to Arduino
MIT License
86 stars 49 forks source link

Add support for not sending any SNI #19

Closed manchoz closed 4 years ago

manchoz commented 4 years ago

Add support for not sending Server Name Indication even when host is a DNS name.

This PR paves the way for supporting TLS servers with home-made/self-created PKI CAs and no SNI extension in server certificate.

This PR has been tested on an Arduino MKR WiFi 1000 and an Arduino MKR WiFi 1010 connected to an in-house MQTT/S broker (mosquitto) with TLS support configured with security files generated via an in-house EasyRSA instance.

The Arduino boards have been programmed with the AWS_IoT_WiFi.ino sketch.

Certificates generation steps:

Rocketct commented 4 years ago

LGTM, tested and works

endorama commented 4 years ago

Hello @manchoz I'm struggling to understand why there is the need to disabled SNI.

I do understand the need for self-signed certificates and home-made PKI (and we need to improve that), but AFAIU disabling SNI can pose a serious security risk (no protection for MITM) even in local networks and is not necessary to setup a home-made PKI.

Can you help me understand?

Rocketct commented 4 years ago

Ciao @endorama was add only to support a customer that need to connect a MKR1000 to his local mqtt broker using SSL/TLS, and was achieved by disabling the SNI, if you think that is to much dangerous we revert the commit.

manchoz commented 4 years ago

Hi @endorama, its mainly intended to reproduce the --insecure option of some popular tools such as curl or mosquitto_sub/pub to help the users test their home-made PKI and self-signed certificates when Certificate Signing Requests and Certificates are not setup with the proper subjectAltNames field (which is the root cause in the 99% of the help requests).

Currently, the parameter is false by default an I think we can make an effort to render the security risk more explicit, eg. renaming the parameter or letting the parameter accept an enum such as CONNECTION_INSECURE or similar. We might also remove the parameter from the constructor and add a ::setInsecureMode() method.

Please, note that the original code already allows insecure connections when using an IPAddress-type address for connection.

I totally agree with you that we need to produce a detailed guide (on par with the Arduino Cloud Provider Examples series) to explain how to properly setup an at-home PKI and how-to generate CSRs and certificates with proper SNI support and how to use it with the Arduino boards (generating the CSR, generating the CRT, uploading the CRT and create the ad-hoc Trusted Anchor).

What do you think?

endorama commented 4 years ago

That option has security implications that are dangerous, is not dangerous per se (as in "giving a gun to a child"). From an Arduino POV, this option used unwisely reduces (if not completely eliminates) any security provided by TLS (in particular for over the internet connections).

are not setup with the proper subjectAltNames field (which is the root cause in the 99% of the help requests)

This is the exact case in which I fear such a field would be used. If we are suggesting to disable SNI checks as a workaround we are doing it wrong :sweat:

To wrap up my considerations:

Please, note that the original code already allows insecure connections when using an IPAddress-type address for connection.

As is reasonable to expect usage of TLS with IP address, may you help me understand the logic flow that happens in such a case? Having TLS certificate issued for IP addresses in relatively uncommon, but supported for public IPs and there is no issuing issue for private PKIs. Is insecure method selected by default if an IP is specified?

endorama commented 4 years ago

@Rocketct @manchoz what do you think? Can we at least implement the ::setInsecureMode() quickly to buy us time to go in deep in identifying other solutions or workarounds?

manchoz commented 4 years ago

@endorama Yes, I will make a new PR ASAP.

aentinger commented 4 years ago

Getting back to @endorama ... When connecting via a NB-IoT network via MKR NB 1500 then you even have to disable SNI because NB-IoT networks don't provide DNS hence you have to no host name either ( https://github.com/arduino-libraries/ArduinoIoTCloud/pull/104/commits/b464613e24084b40b1d9ceb70dc004d81bd27e04 ). An alternative could be to provide a lookup-table (host name for IP) in order to prevent using no SNI when connecting via IP only. Not sure if this will work though.

endorama commented 4 years ago

@aentinger from my understanding of SNI, was born to allow requesting the proper server certificate for HTTP connections: as TLS handshake happens before HTTP it was not possible to have 1 single listeners on a server serving multiple certificates. SNI allows the client to request, during ClientHello to request the server certificate it wants. If this is true the same may happen with MQTT, where TLS happens before MQTT. Would be possible to patch the code so a server name is passed to the ClientHello step?

This would require the lookup table, a sort of /etc/hosts file for the Arduino.

Further reference:

We could try issuing certificates for IP addresses, but unexpected issues may arise (is technically doable but very uncommon) especially due to how our infrastructure is built on AWS.

endorama commented 4 years ago

@manchoz any news on the PR?

endorama commented 4 years ago

Discussed changes have been implemented, thank you all for contributing!