TLS chain validation issue with ISRG Root X1 on nRF7002 using Zephyr

Hi Nordic team,

I'm using the nRF5340 + nRF7002 to securely connect to my backend over HTTPS using Wi-Fi and the native TLS support (mbedTLS).


What works:

  • I can successfully connect to my server using the Let's Encrypt R11 intermediate certificate, provisioned via tls_credential_add(..., TLS_CREDENTIAL_CA_CERTIFICATE, ...).

  • The server sends the full certificate chain (leaf + intermediate), and verification succeeds.


What I want (but can't get to work):

  • I would like to provision only the ISRG Root X1 certificate (the root CA that signs all Let's Encrypt intermediates) to avoid reflashing devices whenever Let's Encrypt rotates intermediates (e.g., R10 to R11 to R14).

  • However, when I provision only the root certificate, TLS handshake fails, even though the server includes the full chain and the chain validates correctly in OpenSSL.


My assumption:

This suggests that mbedTLS (or Zephyr’s TLS socket layer) is not building the full chain from leaf → intermediate → root, and instead only validates the server certificate if its direct issuer is found in the trusted list.


What I’ve tried:

  • Provisioning only ISRG Root X1 → TLS fails

  • Provisioning ISRG Root X1 + R11 together → TLS succeeds (but device remains pinned to R11)

  • Verified that the server sends a valid full chain (checked via openssl s_client)

  • Attempted to find a config like CONFIG_MBEDTLS_CERTIFICATE_CHAIN_PARSING, but it doesn’t seem to exist in current NCS

  • Verified that TLS_PEER_VERIFY is set to REQUIRED

  • Using TLS_CREDENTIAL_CA_CERTIFICATE with correct sec_tag in both provisioning and socket setup


My goal:

I would like to trust only the ISRG Root X1 and have mbedTLS/Zephyr perform proper full-chain validation during handshake, as any standard TLS client would.


My questions:

  1. Is there an official or recommended way to enable full chain validation in Zephyr on the nRF7002 Wi-Fi platform?

  2. Does Zephyr’s net_tls or tls_credentials system support full certificate chain building?

  3. Is mbedTLS in Zephyr expected to always require the direct issuer (intermediate) to be provisioned?

  4. Would using raw mbedTLS APIs (not Zephyr sockets) resolve this limitation?

  5. Are there any planned improvements to make the TLS client more robust for real-world deployments?


I’m happy to share logs, configuration, or a minimal test project if it helps. I'm trying to establish a long-term certificate provisioning strategy that doesn't break every time Let's Encrypt rotates intermediates.

Best regards

  • Hi Lucas,

     

    It is fine that you use AI to get a better overview of the situation, but please; post your input to the AI than the output from it.

    Post your log output, errno 2 is ENOENT, meaning that the socket does not exist.

    Lucas Heitele said:

    Neither option is present or selectable via menuconfig, and even adding them manually doesn’t work (they’re ignored).
    I’m using nRF Connect SDK v2.6.0.

    I strongly recommend that you atleast update to the latest patch version, ie v2.6.4.

    Lucas Heitele said:
    Are these two config options (CONFIG_MBEDTLS_PEM_PARSE_C, CONFIG_MBEDTLS_PEM_WRITE_C) actually needed for the https_client sample on nRF7002 Wi-Fi?

    I did the exact same steps as before, just altered the domain name directly in main.c.

    *** Booting nRF Connect SDK v3.5.99-ncs1-4 ***
    HTTPS client sample started
    Bringing network interface up
    Provisioning certificate
    Connecting to the network
    uart:~$ wifi_cred add SSID WPA2-PSK PASSWORD
    uart:~$ wifi_cred auto_connect 
    [00:00:53.799,316] <inf> wifi_mgmt_ext: Connection requested
    Network connectivity established and IP address assigned
    Looking up api.eversion.tech
    Resolved 194.164.55.211 (AF_INET)
    Connecting to api.eversion.tech:443
    Sent 67 bytes
    Received 165 bytes
    
    >        HTTP/1.1 404 Not Found
    
    Finished, closing socket.
    Network connectivity lost
    Disconnected from the network
    uart:~$

     

    Please post your changes and the log output.

     

    Kind regards,

    Håkon

  • Hi Håkon,

    thanks a lot for your help and hints!
    It turned out the issue was actually due to the mbedTLS heap size. After increasing CONFIG_MBEDTLS_HEAP_SIZE to match the https_client sample, TLS chain validation with only ISRG Root X1 now works as expected.

    Appreciate your quick support!

    Best regards,
    Lucas

Related