OPEnSLab-OSU / SSLClient

🔒Add SSL/TLS functionality to any Arduino library
https://openslab-osu.github.io/SSLClient/index.html
GNU General Public License v3.0
153 stars 46 forks source link

Expected server name was not found in the chain #48

Open jjauzion opened 3 years ago

jjauzion commented 3 years ago

I'm trying to setup mutual TLS on Arduino Nano 33 IoT for a MQTT connection (using this library for MQTT along with SSLClient) but I have this error:

(SSLClient)(SSL_ERROR)(available): Cannot operate on a closed SSL connection.
(SSLClient)(SSL_ERROR)(m_print_br_error): Expected server name was not found in the chain.

Here is how I implement the connection in the arduino code:

WiFiClient wifiClient;
SSLClientParameters mTLS = SSLClientParameters::fromPEM(my_cert, sizeof(my_cert), my_key, sizeof(my_key));
SSLClient my_client(wifiClient, TAs, (size_t)TAs_NUM, A2);
MqttClient mqttClient(my_client);

[...]

// set client session
mqttClient.setCleanSession(true);
mqttClient.setId("mcu_sensor_client" + String(millis()));
mqttClient.setKeepAliveInterval(60 * 1000L);
mqttClient.setUsernamePassword(mqttUser, mqttPassword);

// set lastWill message
strcpy(payload, STATUS_KO);
retain = true;
qos = QOS_STATUS;
mqttClient.beginWill(mcu_status_topic, strlen(payload), retain, qos);
mqttClient.print(payload);
mqttClient.endWill();

// try to connect
if (!mqttClient.connect(broker, port)) {
  Serial.print("MQTT connection failed! Error code = ");
  Serial.println(mqttClient.connectError());
  return mqttClient.connectError();
}
digitalWrite(LED_BUILTIN, LOW);
Serial.println("You're connected to the MQTT broker!");

I use a self signed certificate ca.crt and the mcu cert files mcu_sensor.pem and mcu_sensor.key. I check my certificate with :

I really don't understand why it says server name not found ? Everything looks ok with my certificates

PS: I can share the certificates if it helps (I can re generate new ones after ;)

prototypicalpro commented 3 years ago

Hello! That sounds like a problem with your trust anchors (otherwise known as the certificates.h file). You can generate the correct trust anchor using the pycert_bearssl tool by running:

pycert_bearssl.py convert --no-search ca.crt

Try replacing your current certificates.h file with the one generated by the above command and see if that fixes it.

If that doesn't fix it, verify that the common name (CN) of the server certificate matches the domain name you're connecting to (broker in this case), as the connection won't be valid if it isn't. This verification prevents malicious actors from stealing a certificate from www.google.com and using it for their own malicious site (www.badgoogle.com), as the certificate must match the domain. You can test this issue by using a raw IP address instead of a domain in broker, and if the connection succeeds it means you should re-create your server certificate with the domain name you are connecting to.

jjauzion commented 3 years ago

I did used pycert_bearssl.py to generate my certificates.h

My server has no domain name, it's only running in a local network. I tried to change the CN to the IP of the broker in the broker.pem (certifacte used by the broker), did not worked; I tried also to change the CN of the ca.crt file (the custom Certificate Authority) but still not working. (The IP was already defined in the Subject Alternative Name of the broker.pem)

Those certificates are working just fine using with other MQTT client (one written in Go with [pahoMqtt lib](https://github.com/eclipse/paho.mqtt.golang/tree/master/cmd/stdinpub and the other is telegraf)

As the certificates are working in other clients, my guess would be that something is wrong in the certificates.h, either because I did something wrong when using pycert_bearssl or maybe because of a glitch in the pycert_bearssl code ?

Here are some info on my certificates by running openssl x509 -in mcu_sensor.pem -text

prototypicalpro commented 3 years ago

Which .pem file are you using to generate the certificates.h? If I'm understanding correctly mcu_sensor.pem/key is the client certificate, broker.pem/key is the server certificate and ca.crt is the root for them both: given these assumptions, mcu_sensor.pem/key should be in my_cert/my_key, broker.pem/key should be in the MQTT server config, and ca.crt should be in both the server config and in certificates.h. Is this how you have it setup?

The other issue that could be occurring is with the CN of the server certificate being the same as the CN of the CA. I think strictly speaking it's a valid certificate chain, but I vaguely remember BearSSL not liking that kind of configuration: you might try changing the CN of your CA to something else (it can be anything you want, but I wouldn't use a domain or IP address) and regenerating the server/client certificates. The CN of your client and server certificates look good (assuming you're connecting to 192.168.0.14 in the code).

jjauzion commented 3 years ago

Thanks for helping, sry for the late reply.

If I'm understanding correctly mcu_sensor.pem/key is the client certificate, broker.pem/key is the server certificate and ca.crt is the root for them both: given these assumptions, mcu_sensor.pem/key should be in my_cert/my_key, broker.pem/key should be in the MQTT server config, and ca.crt should be in both the server config and in certificates.h. Is this how you have it setup?

Yes! that's it

The other issue that could be occurring is with the CN of the server certificate being the same as the CN of the CA

I tried, I generated new certificate where CN is different for the CA and the server but I still have the same message.

I changed the MQTT librairy I was using because I had some other issue. With this new library I don't have the same error, the connection just fails (error coming from the mqtt Client: NETWORK_FAILED_CONNECT)

Anyway for the time being I'm not using SSL and will come back on this when I have more time :)

Gretel5X commented 2 years ago

I am having the same issue. I created my own CA certificate ca.crt and signed my server certificate server.crt with it via csr ( I followed this guide). The server.crt has the local IP as CN and the same IP plus the hostname as SAN entries. The CN for ca.crt is different from that (just my name). When I add ca.crt to my browsers trusted authorities and visit the IP, everything is fine and works. When I use pycert_bearssl.py convert --no-search ca.crt to create the header I see no error. But when running the code, I get

(SSLClient)(SSL_WARN)(m_run_until): Terminating because the ssl engine closed
(SSLClient)(SSL_ERROR)(m_start_ssl): Failed to initlalize the SSL layer
(SSLClient)(SSL_ERROR)(m_print_br_error): Expected server name was not found in the chain.

Is it possible to output the expected server name somehow to narrow down the mismatch?

lkjell commented 1 year ago

I believe there is something wrong when handling the SSL/TLS connection. What works for me is that SAN information must be included when creating the server CSR, exclude when creating CRT.

This however is in conlict with most browser. E.g. Edge you need to include SAN when creating CRT. Could be a bug in openssl when creating CSR and CRT.