Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32 after a few days starts returning error Certificate is expired or not yet valid #27

Closed
goseese opened this issue Nov 10, 2020 · 15 comments
Labels
question Further information is requested

Comments

@goseese
Copy link

goseese commented Nov 10, 2020

I have a sketch that runs on many ESP32 devices with a W5500.

All devices have been running fine for approx 1 month with no issues.

Recently all the devices have started reporting the following error when attempting to connect to my server.

20:53:51.515 -> (SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
20:53:51.515 -> (SSLClient)(SSL_WARN)(m_run_until): Terminating because the ssl engine closed
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_start_ssl): Failed to initlalize the SSL layer
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_print_br_error): Certificate is expired or not yet valid.

The server ssl certificate is a letsencrypt certificate and is working properly. Double checking the certificate expire data is about 90 days from the current date. The certificates have recently renewed.

First I forced the certificate to renew again, and rebooted the devices, no change.

Then I re-uploaded firmware to one of the devices. No changes were made to the firmware. The trust anchor was not changed. - The device started working.

I then forced the certificate to renew again. This did not cause the problem to come back for that device and all other devices were un-changed.

As a check I exported the trust anchor again and compared to the existing trust anchor. The trust anchor content did not change.

So my problem is I have many devices that are failing with the stated error "Certificate is expired or not yet valid". The only fix seems to be re-uploading unchanged firmware to the device.

Perhaps there is something with timestamp that validates the certificate at compile time and I need some way to update that time stamp?

The devices do not have an RTC and I do not set the time on them. I Can make a code change to do that, however uploading new code temporarily solves the issue so it would be hard for me to verify that is a fix.

@goseese goseese added the question Further information is requested label Nov 10, 2020
@prototypicalpro
Copy link
Member

Perhaps there is something with timestamp that validates the certificate at compile time and I need some way to update that time stamp?

The timestamp is fixed at the last compile time, and that's probably what is causing the issue. SSLClient uses the compilation timestamp as the "current time" in leu of a real time clock, which is why re-uploading fixed the error but restarting didn't:

/*
* Set a fixed epoch time to validate certificates against.
* Since we are working with an embedded device, there isn't
* really a reliable source of time. To remedy this, we simply
* store the time this program was compiled, and assume that
* any certificate valid under that time is also valid at the
* current time. This is vulnerable to the use of expired
* certificates, however an attacker would have to use a
* certificate valid after the compile date, which is fairly
* difficult given the lifespan of projects here at the lab.
* For now, this solution is good enough.
*/
br_x509_minimal_set_time(xc,
// days since 1970 + days from 1970 to year 0
(UNIX_TIMESTAMP_UTC / SEC_PER_DAY) + 719528UL,
// seconds over start of day
UNIX_TIMESTAMP_UTC % SEC_PER_DAY);

Given this, I would say that your issue is expected behavior, at least for the moment. Are you looking for a function to change the fixed timestamp? I did notice that the documentation doesn't mention this behavior anywhere, so I can go ahead and fix that.

@goseese
Copy link
Author

goseese commented Nov 10, 2020

So if I write a function that pulls in an epoch time stamp and sets the ESP32 current time to that value and then passes that timestamp to the validation function that should solve this issue?

@prototypicalpro
Copy link
Member

prototypicalpro commented Nov 10, 2020

I think so. I went ahead and added a setVerificationTime function on master which you can use to get the timestamp into SSLClient. It accepts the weird time format that BearSSL uses, which unfortunately isn't epoch but is pretty close. The UNIX_TIMESTAMP_UTX macro is an epoch value in the code I linked above, so you can use the same math to convert your epoch timestamp into BearSSL's format. Give that a shot and tell me what you think.

@michaelhwhitten
Copy link

Hi - I've got self-signed certificates with an extremely long expiration date set. Will I be running into this issue after devices have been in the field a few months as well?

@prototypicalpro
Copy link
Member

Hi - I've got self-signed certificates with an extremely long expiration date set. Will I be running into this issue after devices have been in the field a few months as well?

No, this issue will only occur if a certificate expires or is replaced while the device is operating. Since you control the certificate chain, so long as you never replace the certificates without re-flashing the devices you should be fine.

@michaelhwhitten
Copy link

Thanks.

@woodlist
Copy link

Once again thanks for monumental job. I have tried too many alternative libraries, but only given library's performance got just fine.
I got worked it with TinyGSM library. For timing subject, it would be perfect to get implemented one line command that will use the result of beneath command from TinyGSM:
String timefromNet = modem.getGSMDateTime(DATE_FULL); SerialMon.println("Current Network Time: " + timefromNet);
Which returns a string type variable, like this (Copy/Pasted from terminal window):
Current Network Time: 21/04/19,12:19:36+16

@mlrochaa23
Copy link

Sorry for the silly questions but I'm newbie and I'm having the same problem of @goseese.

Should I call void setVerificationTime (uint32_t days, uint32_t seconds); function before (!client.connect(host, httpsPort)) ?

@HolgerBri
Copy link

Hi,
I am also using TinyGSM. Is there an easy way to get the days for current date calculated if full date is available?
Best regards
Holger

@bvernham
Copy link

So I added the following to when I connection to the WIFI module is established.
unsigned long WIFITime = WiFi.getTime(); sslClient.setVerificationTime((uint32_t)((WIFITime / (SECS_PER_DAY)) + 719528UL), (uint32_t)(WIFITime % (SECS_PER_DAY)));

Now I get the following messages:
Connect failed(SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
(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): Certificate is expired or not yet valid.

When does "setVerficationTime" need to be called? I am effectively using the conversion for day to 1/1/0 from the BEARSSL calc. When I use compile time there is no issue but when I set the time in the code with the same calc it says the Cerficate is expired.

What am I doing wrong?

Thanks

Bruce

@zenbooster
Copy link

I think so. I went ahead and added a setVerificationTime function on master which you can use to get the timestamp into SSLClient. It accepts the weird time format that BearSSL uses, which unfortunately isn't epoch but is pretty close. The UNIX_TIMESTAMP_UTX macro is an epoch value in the code I linked above, so you can use the same math to convert your epoch timestamp into BearSSL's format. Give that a shot and tell me what you think.

...
    unsigned long epoch = TWiFiStuff::getEpochTime();
    const static unsigned long sec_per_day = 60 * 60 * 24;
    p_ssl_cli->setVerificationTime(
        // days since 1970 + days from 1970 to year 0
        epoch / sec_per_day + 719528UL,
        // seconds over start of day
        epoch % sec_per_day
    );
    if(p_mqtt_cli->connect(server.c_str(), port))
    {
...

@StefanoPierini
Copy link

I have exactly the same problem you have. Did you find a solution?

I find epoch from UTP server and convert it via the following command:

        // days since 1970 + days from 1970 to year 0
        //(unsigned long) (epoch / sec_per_day ),
        (uint32_t) (epoch / sec_per_day + 719528UL),
        // seconds over start of day
        (uint32_t) epoch % sec_per_day
        );

If someone has a solution, please share it :)

So I added the following to when I connection to the WIFI module is established. unsigned long WIFITime = WiFi.getTime(); sslClient.setVerificationTime((uint32_t)((WIFITime / (SECS_PER_DAY)) + 719528UL), (uint32_t)(WIFITime % (SECS_PER_DAY)));

Now I get the following messages: Connect failed(SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway... (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): Certificate is expired or not yet valid.

When does "setVerficationTime" need to be called? I am effectively using the conversion for day to 1/1/0 from the BEARSSL calc. When I use compile time there is no issue but when I set the time in the code with the same calc it says the Cerficate is expired.

What am I doing wrong?

Thanks

Bruce

@Decezaris
Copy link

Despite possessing a valid certificate, I'm encountering an ongoing issue. Previously, everything operated smoothly, but after a span of 67 days, all my devices unexpectedly disconnected. I rely on an AWS IoT Core auto-signed certificate, depicted below, yet the outcome remains the same as shown in the logs bellow. After re-flashing the devices, without any code changes, back to work again.

Certificate

Captura de Tela 2024-01-05 às 11 32 48

Logs

Captura de Tela 2024-01-05 às 11 31 18

@FischerDave
Copy link

I had the same problem as in the previous comment (#27 (comment)), also on AWS IoT Core, with authenticated certificates. In my case, rewriting does not solve the problem either.

@monolith-sylee
Copy link

I also suffered frome the same problem. But I've solved this problem, and I'll talk about how I've solved it.
First, the problem is solved by changing the contents of the file TLS12_only_profile.c under the SSLClient/src document so that the compiler can understand it anew. For example, adding a space key to the empty space of the file.

But, This method is not a fundamental problem-solving method.

As mentioned in "StefanoPierini commented on May 16, 2023", it was resolved using setVerificationTime.

The location of the function I used was executed before "mqtt server connect".

To reveal a bit of the sauce
**
if (!wclient.connected())
{
wclient.clearWriteError();
Serial.print("$0,Attempting MQTT connection...;");
// Serial.printf(" %d \n",maintainFlag);
clientStateFlag = wclient.state();
wifiClientSSL.setVerificationTime(getDayValue() + 719528UL, 0);
if (wclient.connect(NetworkClientId.c_str()))
{
**

My development environment uses "VSCode PlatformIO IDE". I am using the libraries of "SSLClient" and "subclient".

I hope this comment from me will be helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests