Can PEM certificates be used with MBEDTLS?

The documentation for CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT in nRF Connect SDK says:

By default only DER (binary) format of certificates is supported. Enable this option to enable support for PEM format.

And lists, amongst other things, CONFIG_MBEDTLS_BUILTIN as a dependency. But in ncs, it seems the builtin MBEDTLS cannot be used, and CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY is the default instead??

So after an hour of going around in circles with PEM, it seems it's simply not possible with MBEDTLS and the nRF Connect SDK. But I can't find a whisper on this topic anywhere, except a couple of words coming to a similar conclusion the PEM config here, and a comment on the BUILTIN clash and a strange diversion to OpenThread here. Surely I'm not the first to try to use PEM certificates for TLS with ncs?

At this stage I don't know which of these configs are leading me astray, or indeed whether it's specific to the nrf5340 I'm targeting (if so, why?).

Parents Reply Children
  • How are you planning to use PEM format in your applications?

    To conduct a HTTP / TLS session with a remote server over WiFi (using a nrf7002). So we need to load a CA certificate to complete the TLS handshake. If we can handle it in PEM format, then great.

    However, the security implementation in NCS supports PEM natively.

    Ah! Thank you. That was one of my theories, but apart from your valuable words, I could not find a scrap of evidence for it! All the docs indicate otherwise, such as this one, which says the opposite: developer.nordicsemi.com/.../sockets.html

    For an example of how .pem files are used, please refer to the AWS IoT sample.

    Ah, I see this is just a thin wrapper around the hard to find lib_aws_iot, which is just a thin wrapper around MQTT Helper. There, finally I see just one statement on PEM format, which actually says it's the default! Since all MQTT Helper does is pass the certificate verbatim to tls_credential_add(), I arrive at the conclusion you so succinctly stated.

    tls_credential_add() offers no feedback on whether what you've given it is garbage or not, so it's been difficult to get to the bottom of this. Have I missed a reference or self-help method somewhere, or is this literally the first time this information has been surfaced?

  • liteyear said:
    Ah! Thank you. That was one of my theories, but apart from your valuable words, I could not find a scrap of evidence for it! All the docs indicate otherwise, such as this one, which says the opposite: developer.nordicsemi.com/.../sockets.html

    Right. As you might have known, the nRF Connect SDK is based on the Zephyr RTOS

    The documentation you linked here is from the Zephyr part of the SDK. It would then make sense that it reflects the Zephyr implementation of Mbed TLS, where PEM is not supported by default, and CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT is necessary.

    In NCS, the nRF Security implementation is added. Information about that is supposed to be in the "nRF Connect SDK" side of the documentation. Features added or changed in NCS might cause some of the documentation in the Zephyr side to become incorrect, as you see here.

    liteyear said:
    tls_credential_add() offers no feedback on whether what you've given it is garbage or not, so it's been difficult to get to the bottom of this. Have I missed a reference or self-help method somewhere, or is this literally the first time this information has been surfaced?

    Do you mean getting to the bottom of how tls_credential_add() works, or how to find that the nRF Security implementation of Mbed TLS supports PEM by default?

    If you mean the documentation, then you might have not missed anything. Unfortunately, we still have some gaps in our documentation. This is one of those that we should work on. I will note this with our teams. Our apology for the inconvenience.

    Hieu

  • Right, thanks very much. I try to tread very carefully knowing there's considerable baggage, so I read the tea leaves as much as possible. Seems I came unstuck on this one. Thanks for the tips.

    Yeah, I was just hoping to "figure out" what tls_credentials_add() accepts. Documentation would be great, but I realise that's a challenge. Descriptive error messages and logging are the next best thing, but I'm not seeing a lot of those. So now that I know where to look, I'm just stepping through the source of the truth - the source! It's too complicated to do on paper, so I'm using the debugger.

    My first realisation is when I stepped through to here:

    https://github.com/nrfconnect/sdk-mbedtls/blob/72868c6f1421afa92cba9f6fe6d1a3f108c174b7/library/x509_crt.c#L1412

    To be identified as a PEM certificate, it must start with exactly "-----BEGIN CERTIFICATE-----", and crucially, include a null terminator at the end (ie. the buffer passed to tls_credentials_add() has to be a C string and credLen must be "strlen + 1"). I think it's the opposite for DER (binary, no terminator). Excellent info! Saves me iterating on a dozen variations hoping for the best.

    Next realisation came here:

    https://github.com/nrfconnect/sdk-mbedtls/blob/72868c6f1421afa92cba9f6fe6d1a3f108c174b7/library/pem.c#L265

    The footer "-----END CERTIFICATE-----" must also appear in the string (not necessarily at the end). There must be a line ending after the header of " \r\n", "\r\n" or "\n". There doesn't have to be a line ending after the footer, but if there is it is included in the size calculation. Anything after that is ignored.

    Next realisation came here:

    https://github.com/nrfconnect/sdk-mbedtls/blob/72868c6f1421afa92cba9f6fe6d1a3f108c174b7/library/pem.c#L386

    "\r\n" or "\n" are allowed anywhere between the header and footer, but not spaces which are only allowed at the end. Otherwise every character must be base64 decodable.

    The library then dynamically allocates enough memory to hold the decoded result, before parsing it and adding it to chain in the tls context, allocating memory for the parts it needs. The decoded buffer is then freed.

    And now I see multiple headers and footers can be concatenated (hence the "size calculation" above), so multiple certificates can be provided at once.

    Getting there...

  • Finally, after allocating 48000 bytes to CONFIG_MBEDTLS_HEAP_SIZE (and desperately stealing from the heap mem pool to make it fit!), I have successfully established TLS to a remote server using a PEM CA certificate.

    Thanks for your help - PEM works!

Related