Juerd / ESP-WiFiSettings

WiFi Manager for the ESP32 Arduino environment
Other
166 stars 34 forks source link

WiFiSettings.string() seems to encode the string in some way #18

Closed SanderVanhove closed 3 years ago

SanderVanhove commented 3 years ago

I'm trying to get CA root certificates configured using the WiFiSettings.string(), but I keep getting the error that the certificate is invalid, while hardcoding the certificate string in code works.

Gist example:

String hardcoded_cert = "-----BEGIN CERTIFICATE-----\nMIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1owTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XCov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpLwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+DLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5ysR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBcSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2qlPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TNDTwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26ZtuMA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuGWCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9Ohe8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFCDfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n-----END CERTIFICATE-----\n";

void setup() {
    /*
        Setup WiFiSettings
    */

    // Set the value of this string the same as the hardcoded_cert
    String rest_cert = WiFiSettings.string("rest_cert", 2000, "", T.config_rest_cert);
    // Noticed that `\`s gets escaped
    rest_cert.replace("\\n", "\n");

    WiFiClientSecure wificlient;

    // The one from the settings does not work
    wificlient.setCACert(rest_cert.c_str());

    // The hardcoded cert works
    wificlient.setCACert(hardcoded_cert.c_str());

    /*
        Begin and wait for WiFi Connection
    */

    // Will error with the rest_cert configured
    wificlient.connect("webscripts-io.waylay.io", 443)
}

I see in the library that the setting values get stored to disk, is it possible that this step encodes the string in some way? Maybe I'm missing something obvious.

Juerd commented 3 years ago

Sander Vanhove skribis 2021-06-04 6:27 (-0700):

I'm trying to get CA root certificates configured using the WiFiSettings.string(), but I keep getting the error that the certificate is invalid, while hardcoding the certificate string in code works.

To verify your theory that some kind of encoding is going on, please try to do a byte-by-byte comparison between the hard-coded string and the one you get from WiFiSettings.string().

String hardcoded_cert = "...";

This is a global, which is still alive after setup() has finished.

void setup() { String rest_cert = WiFiSettings.string("rest_cert", 2000, "", T.config_rest_cert);

This is a local variable, the memory of which is reused after setup() has finished.

wificlient.setCACert(rest_cert.c_str());

.c_str() returns a pointer to the memory location which after setup() has finished is likely to no longer contain the certificate.

This is important, because .setCACert() does not copy the string; it just stores the pointer. If the string is used after setup() is done, that no longer works.

wificlient.setCACert(hardcoded_cert.c_str());

This pointer, however, remains pointing to the hard coded string.

If you use the certificate after setup(), then that will probably not work.

wificlient.connect("webscripts-io.waylay.io", 443)

In your example, the .connect() is in setup(); is that the case in your actual program as well? If the .connect() is NOT in .setup() in your actual program, please try to make rest_cert a global variable or static variable to verify if the dangling pointer is the cause of the issue.

What is the exact error that you get?

I see in the library that the setting values get stored to disk, is it possible that this step encodes the string in some way? Maybe I'm missing something obvious.

I'm not ruling it out, but I'm not aware of any encoding going on. Please try to check the values byte by byte to see where they differ.

Juerd

SanderVanhove commented 3 years ago

Hey Juerd, thanks for the quick response! 😁

This is a local variable, the memory of which is reused after setup() has finished.

This was indeed the problem! The .connect() function is indeed called outside of the setup(). It has been some time since I programmed C++ to be honest, but then again I was assuming the ssl client would copy the certificate somewhere.

Thank you so much for helping out, I changed rest_cert to a global variable and everything runs smoothly now 😊