nrf5340 NCS 2.8 cannot get TLS socket to load CA certif due to net_sock_tls / mbedtls error -0x262e

Using Zephyr in NCS 2.8 on nrf5340/nrf7002 wifi combo, and trying to get https to work. I'm using the option where the TLS setup is done in the socket layer (enabled in prj.conf)

# use TLS in socket directly
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_TLS_CREDENTIALS=y
CONFIG_TLS_MAX_CREDENTIALS_NUMBER=10
CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS=10

However, I cannot get this to parse a server certificate (.der or .pem formats). Every time it fails when it tries to parse the certificate to load the url, with the following:

[00:00:24.298,767] <inf> app: host [timeapi.io/api/time/current/zone?timeZone=Europe%2FParis&id="app.sysctrl.checkhttp"&value="00:00:00"] port [NULL] path [/api/time/current/zone?timeZone=Europe%2FParis&id="app.sysctrl.checkhttp"&value="00:00:00"] query [?timeZone=E
[00:00:24.322,906] <inf> app: Looking up host [timeapi.io][443], asking for path[/api/time/current/zone?timeZone=Europe%2FParis&id="app.sysctrl.checkhttp"&value="00:00:00"]

[00:00:24.360,046] <inf> app: Resolved 86.105.246.247 (AF_INET)
[00:00:24.366,485] <inf> app: httpmgr: checking certs/ca for certs
[00:00:24.376,586] <inf> app: httpmgr : registered cert [certs/ca/timeapi.io.der]
[00:00:24.387,054] <inf> app: httpmgr : registered cert [certs/ca/www.infrafon.cloud.der]
[00:00:24.395,996] <inf> app: httpmgr: checking certs/cli for certs
[00:00:24.403,930] <inf> app: httpmgr: added 2 TLS certificates
[00:00:24.410,308] <inf> app: httpmgr : TLS setup OK on socket
[00:00:24.416,595] <inf> app: Connecting to timeapi.io:443

[00:00:24.455,474] <err> net_sock_tls: Failed to parse CA certificate, err: -0x262e
[00:00:24.463,867] <wrn> app: Failed to connect socket (-1), [22]
[00:00:24.470,947] <wrn> app: uimgr : http req fails to start to time;timeapi.io/.../zone

Note:

 - I'm using timeapi.io as an easy test URL, not really because this is my target server!

 - at init, I load (once) the certificates from my flash FS by mallocing space for the data and then calling tls_credential_add() to give the buffer to the socket TLS system referenced by a "security tag" id for each one

 - when I create the socket, I setsockopt(TLS_SEC_TAG_LIST) it with the list of all the security tag values I previously added the certificates under so it can reference them.

The problem occurs when I call connect() on the socket, as that's when the TLS layer tries to parse the certificates....

In the debugger; the fail is in 

x509.c : mbedtls_x509_crt_parse()

which calls 

mbedtls_x509_crt_parse_der()
which ends up in 
x509_crt_parse_der_core()
As far as I can tell, its when it calls in line 1168:
mbedtls_x509_get_sig_alg() (in x509.c)
that it gets a return value of  -0x262e. in this function This is the add of 
MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + the ret from 
mbedtls_oid_get_sig_alg()
This is a function created by lovely macro cin oid.c:
int mbedtls_oid_get_sig_alg(const mbedtls_asn1_buf *oid, mbedtls_md_type_t * md_alg, mbedtls_pk_type_t * pk_alg) {
  const oid_sig_alg_t *data = oid_sig_alg_from_asn1(oid);
  if (data == ((void *)0))
       return -0x002E;
  *(md_alg) = data->md_alg;
  *(pk_alg) = data->pk_alg;
  return 0;
}
(btw this kind of macro *** really makes the debugger hard to follow...)
The oid_sig_alg_from_asn1() function which tries to extract the OID of the certificate's signature algo from the asn.1 and map it to the mbedtls types... is another macro defined function in oid.c:
FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg)
which gives us:
static const oid_sig_alg_t *oid_sig_alg_from_asn1( const mbedtls_asn1_buf *oid) {
  const oid_sig_alg_t *p = (oid_sig_alg);
  const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p;
  if (p == ((void *)0) || oid == ((void *)0))
    return ((void *)0);
  while (cur->asn1 != ((void *)0)) {
    if (cur->asn1_len == oid->len && memcmp(cur->asn1, oid->p, oid->len) == 0) {
      return p;
    }
    p++;
    cur = (const mbedtls_oid_descriptor_t *) p;
  }
  return ((void *)0);
}
Unpacking this, its searching for the oid given in the certificate in a static array (oid_sig_alg in oic.c) generated with a load of ifdefs depending on which crypto algos are compiled in...
The certificate is using PKCS#1 SHA-256 with RSA (the public key of the certificate of timeapi.io is 2048 size) according to chrome's handy popup...
And indeed, in my oid.c, only sha256 with ECDSA algos are enabled...in fact no RSA algo is enabled (MBEDTLS_RSA_C is not defined)
All this hidden behinf that errno=-22 from connect().... lucky I got that nice error log from the TLS layer eh?
So, it seems I just need to define :
MBEDTLS_RSA_C
However, the saga continues - this define is already set in the mbedtls config file I select (zephyr/modules/mbedtls/config/config-mini-tls1_2.h) in my prj.conf:
CONFIG_NRF_SECURITY=n
CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY=n
CONFIG_CUSTOM_MBEDTLS_CFG_FILE=y
CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y
However, visual code studio tells me that in the build NRF_SECURITY is 'y', and the MBEDTLS_CFG_FILE is set to 'nrf-config.h'!
The only place I can find this file is in
build/generated/library_nrf_security_psa/nrf-config.h
... and it indeed does NOT define MBEDTLS_RSA_C....
(and why does it all have to be so complicated and wrapped in 27 layers of kconfig files and macros???)
So finally my question : how do I get the nrf wrappers round the zephyr KConfig to accept that I want to use a specific mbedtls config, which includes MBEDTLS_RSA_C?
Also, it seems the sockets TLS code is hardcoded to use mbedtls functions : is there an alternative (which might take up less flash space, eg tinycrypt?
Naively I though I could just do
CONFIG_NRF_SECURITY=n
CONFIG_MBEDTLS=n
CONFIG_TINYCRYPT=y
but no joy (although maybe this is because its forcing mbedtls/nrf_security?)


Parents
  • So finally my question : how do I get the nrf wrappers round the zephyr KConfig to accept that I want to use a specific mbedtls config, which includes MBEDTLS_RSA_C?

    If I add CONFIG_MBEDTLS_RSA_C=y, then my flash overflows...

    prj.conf:

    CONFIG_NRF_SECURITY=y
    CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY=y
    # TLS configuration - don't want everything in mbedtls as far too big
    #CONFIG_CUSTOM_MBEDTLS_CFG_FILE=y
    #CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
    CONFIG_MBEDTLS=y
    CONFIG_MBEDTLS_DTLS=n
    CONFIG_MBEDTLS_TLS_VERSION_1_2=y
    CONFIG_MBEDTLS_RSA_C=y

    So, I thought I'd remove EC crypto (as I can use just RSA certificates)? 

    CONFIG_MBEDTLS_ECDH_C=n
    but KConfig is conflicted about this.
    warning: MBEDTLS_PK_WRITE_C (defined at C:/ncs/v2.8.0/nrf\subsys\nrf_security\Kconfig.legacy:875, C:/ncs/v2.8.0/zephyr/modules/mbedtls\Kconfig.tls-generic:470, modules\mbedtls\Kconfig.tls-generic:470) has direct dependencies (MBEDTLS_PK_C && NRF_SECURITY) || (MBEDTLS_BUILTIN && MBEDTLS_CFG_FILE = "config-tls-generic.h" && MBEDTLS) || (MBEDTLS_BUILTIN && MBEDTLS_CFG_FILE = "config-tls-generic.h" && MBEDTLS && 0) with value n, but is currently being y-selected by the following symbols:
    - WIFI_NM_WPA_SUPPLICANT_CRYPTO_ALT_LEGACY_NCS (defined at C:/ncs/v2.8.0/zephyr/modules/hostap/Kconfig:215, modules/hostap/Kconfig:215, modules\hostap\Kconfig:215), with value y, direct dependencies <choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND> || <choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND> || <choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND> (value: y), and select condition <choice WIFI_NM_WPA_SUPPLICANT_CRYPTO_BACKEND> (value: y)
    Adding
    CONFIG_MBEDTLS_ECDSA_C=n
    fixed KConfig, but now the compile fails:
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c: In function 'crypto_ec_key_parse_priv':
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2354:5: error: unknown type name 'mbedtls_pk_context'; did you mean 'mbedtls_dhm_context'?
     2354 |     mbedtls_pk_context *ctx = os_malloc(sizeof(*ctx));
          |     ^~~~~~~~~~~~~~~~~~
          |     mbedtls_dhm_context
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2357:5: warning: implicit declaration of function 'mbedtls_pk_init'; did you mean 'mbedtls_mpi_init'? [-Wimplicit-function-declaration]
     2357 |     mbedtls_pk_init(ctx);
          |     ^~~~~~~~~~~~~~~
          |     mbedtls_mpi_init
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2361:9: warning: implicit declaration of function 'mbedtls_pk_parse_key'; did you mean 'mbedtls_ecp_write_key'? [-Wimplicit-function-declaration]
     2361 |     if (mbedtls_pk_parse_key(ctx, der, der_len, NULL, 0, mbedtls_ctr_drbg_random, crypto_mbedtls_ctr_drbg()) == 0)
          |         ^~~~~~~~~~~~~~~~~~~~
          |         mbedtls_ecp_write_key
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2365:5: warning: implicit declaration of function 'mbedtls_pk_free'; did you mean 'mbedtls_mpi_free'? [-Wimplicit-function-declaration]
     2365 |     mbedtls_pk_free(ctx);
          |     ^~~~~~~~~~~~~~~
          |     mbedtls_mpi_free
    In file included from C:/ncs/v2.8.0/modules/crypto/mbedtls/include/mbedtls/oid.h:17,
                     from C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2371:
    C:/ncs/v2.8.0/modules/crypto/mbedtls/include/mbedtls/pk.h: At top level:
    C:/ncs/v2.8.0/modules/crypto/mbedtls/include/mbedtls/pk.h:310:6: warning: conflicting types for 'mbedtls_pk_init'; have 'void(mbedtls_pk_context *)'
      310 | void mbedtls_pk_init(mbedtls_pk_context *ctx);
          |      ^~~~~~~~~~~~~~~
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2357:5: note: previous implicit declaration of 'mbedtls_pk_init' with type 'void(mbedtls_pk_context *)'
     2357 |     mbedtls_pk_init(ctx);
          |     ^~~~~~~~~~~~~~~
    C:/ncs/v2.8.0/modules/crypto/mbedtls/include/mbedtls/pk.h:323:6: warning: conflicting types for 'mbedtls_pk_free'; have 'void(mbedtls_pk_context *)'
      323 | void mbedtls_pk_free(mbedtls_pk_context *ctx);
          |      ^~~~~~~~~~~~~~~
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2365:5: note: previous implicit declaration of 'mbedtls_pk_free' with type 'void(mbedtls_pk_context *)'
     2365 |     mbedtls_pk_free(ctx);
          |     ^~~~~~~~~~~~~~~
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c: In function 'crypto_mbedtls_pk_parse_subpubkey_compressed':
    C:/ncs/v2.8.0/modules/lib/hostap/src/crypto/crypto_mbedtls_alt.c:2473:14: warning: implicit declaration of function 'crypto_mbedtls_short_weierstrass_derive_y' [-Wimplicit-function-declaration]
     2473 |           || crypto_mbedtls_short_weierstrass_derive_y(ecp_kp_grp, Y, (*p & 1));
          |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    [246/718] Building C object zephyr/lib/libc/common/CMakeFiles/lib__libc__common.dir/source/time/asctime.c.obj
    ninja: build stopped: subcommand failed.
    FATAL ERROR: command exited with status 1: 'C:\ncs\toolchains\2d382dcd92\opt\bin\cmake.EXE' --build 'C:\work\dev\if-device-nrf53\cc1-med\build'
    How can I get a minimum TLS1.2 capable mbedtls build?
  • Thanks, but 

    a) the wif connection is working fine thanks

    b) the 'https' client sample is where I started from

    And lets be clear, the https client sample is not even close to a real usable https client. It's a http client implementation that is so basic and dumb that it's not useful for any real https server (no handling of headers, async operation, etc), it serves only to say 'look, you can ping a https server on a nordic chip'. As the basis for any real application its just a dead-end. And as the selection of the prj.conf options are not explained (why these options, and what the impacts are) it doesn't even serve as a good training example!

    Therefore as soon as it becomes necessary to work in the real world it doesn't answer questions like 'how to get tls to work in a restricted memory size' or 'which KConfig options do what' and in particular 'between all the different architectural options (mbedtls 'standard', 'zephyr', 'nrf-security', with/without 'PSA') which are useable and which are not.

    So, to return to my question: what is the correct KConfig setup to get a minimum TLS1.2 setup (ie functionally as per the config-min-tls1_2.h config file) when using nrf-security (as this seems to be obligatory) and PSA mode?

    thanks

  • Hi, 

    BrianW said:
    what is the correct KConfig setup to get a minimum TLS1.2 setup (ie functionally as per the config-min-tls1_2.h config file) when using nrf-security (as this seems to be obligatory) and PSA mode?

    Why do you insist to use the config-min-tls1_2.h config file?

    The default configs setting of the http_client sample can support TLS 1.2, and the MBEDTLS_RSA_C is also shown in the build/generated/library_nrf_security_psa/nrf-config.h

    -Amanda H.

  • Why do you insist to use the config-min-tls1_2.h config file?

    Because I am very short of flash space, and the networking code is a huge reason for that. So I want to ensure I only have the minimum set of crypto to run tls1.2 with RSA certifs.

    For example, the https_client sample has exactly 372 lines in its app source file (main.c), but builds an image that is 658kB (>75% of available flash on an nrf5340). And the default RAM setup uses >75% of available RAM!

    Memory region Used Size Region Size %age Used
    FLASH:         658596 B      848 KB    75.84%
    RAM:           310240 B      400 KB    75.74%

    And thats only zephyr+networking! If I also want NFC, BLE GATT server, BLE scanning, USB etc (and maybe some space for my app code eh?) it just doesn't work with the sample config.

    So I need to trim the network to the minimum for TLS1.2 (and this is obviously a common requirement as mbedtls went to the trouble of creating a specific config file for that!).

    Any ideas on a config for that?

    Also, wpa_supp has a lot of functionality- is it possible to reduce its footprint? (for example, I really only need to handle WPA2-PER type APs, not all the other possibilities...)

Reply
  • Why do you insist to use the config-min-tls1_2.h config file?

    Because I am very short of flash space, and the networking code is a huge reason for that. So I want to ensure I only have the minimum set of crypto to run tls1.2 with RSA certifs.

    For example, the https_client sample has exactly 372 lines in its app source file (main.c), but builds an image that is 658kB (>75% of available flash on an nrf5340). And the default RAM setup uses >75% of available RAM!

    Memory region Used Size Region Size %age Used
    FLASH:         658596 B      848 KB    75.84%
    RAM:           310240 B      400 KB    75.74%

    And thats only zephyr+networking! If I also want NFC, BLE GATT server, BLE scanning, USB etc (and maybe some space for my app code eh?) it just doesn't work with the sample config.

    So I need to trim the network to the minimum for TLS1.2 (and this is obviously a common requirement as mbedtls went to the trouble of creating a specific config file for that!).

    Any ideas on a config for that?

    Also, wpa_supp has a lot of functionality- is it possible to reduce its footprint? (for example, I really only need to handle WPA2-PER type APs, not all the other possibilities...)

Children
  • CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"

    That config file is only usable with MBEDTLS_BUILTIN. It can't use a preconfigured header file with our system. You can however configure the features equivalent to what is the content of this file. 

    BrianW said:
    is it possible to reduce its footprint?

    You can refer to the Memory footprint optimization

  • You can refer to the Memory footprint optimization

    Yes, I have already applied the principals from this page: however it does NOT offer any information about reducing the size of the crypto or wpa-supp code.

    I have already found that 2 methods can be useful : reducing the 'compiled in logs level' in zephyr modules (using CONIFG_XXX_LOG_LEVEL_WRN=y to avoid info logs for module XXX) and disabling wpa-supplicant features (WPA3/AP/WEP/P2P etc). 

    That config file is only usable with MBEDTLS_BUILTIN. It can't use a preconfigured header file with our system. You can however configure the features equivalent to what is the content of this file. 

    Any examples of a config that does that? I would like to disable EC crypto for example, but even when I request this

    CONFIG_MBEDTLS_ECP_C=n
    The autoconf.h still has
    #define CONFIG_MBEDTLS_ECP_C 1
    which is not the case for the 'mini' TLS config!
  • So, today I have managed to get a state where:

    - can build the app

    - can parse RSA certificates if they only have a key up to 2048 bits

    - can do a https request successfully to a web server when its CA chain only includes certs that have RSA keys <2048 bits

    Example url that works (16 jan 2025)

    https://eu.httpbin.org/get

    but I cannot manage to build TLS code that can:

    - parse a certificate with a 4096bit RSA key (gives a "Failed to parse CA certificate, err: -0x3b00)

    - parse a certificate with a EC key (not sure what algo)

    - connect to a server where the certificate chain will include a 4096 bit key (code gets an error during the TLS connect phase "net_sock_tls: TLS handshake error: -0x2700")

    - connect to a server using a certificate with EC algo (again, not sure of the algo)

    Example of a site using EC certificates (16 jan 2025):

    https://example.com

    Note : site USED to use a RSA certifcate with 2048 bits, and therefore used to work for me... the new certificate is marked as 'valid from 15/1/2025!

    Example of a site url using 4096 bit RSA certificates in its chain:

    https://timeapi.io/api/time/current/zone?timeZone=Europe%2FParis

    (another thing I don't understand : if I give the TLS the certificate of the site itself, it doesn't seem to work, I have to give it the certif of one of the CA in the signature chain above it? Is this normal?)

    I cannot find a prj.conf that enables either 4096bit RSA, or EC keys for whatever example.com uses.

    Relevant chunk of prj.conf : note the commented out keys are stuff I tried but it broke the build in one way or another. Networking is wifi (nrf7002) with wpa-supp from NCS 2.8.

    CONFIG_NRF_SECURITY=y
    CONFIG_MBEDTLS_LIBRARY_NRF_SECURITY=y
    # TLS configuration - don't want everything in mbedtls as far too big
    #CONFIG_CUSTOM_MBEDTLS_CFG_FILE=y
    #CONFIG_MBEDTLS_CFG_FILE="config-mini-tls1_2.h"
    CONFIG_MBEDTLS=y
    CONFIG_MBEDTLS_DTLS=n
    CONFIG_MBEDTLS_TLS_VERSION_1_2=y
    CONFIG_MBEDTLS_RSA_C=y
    CONFIG_MBEDTLS_ECP_C=n
    #CONFIG_MBEDTLS_ECDH_C=n    this breaks kconfig
    #CONFIG_MBEDTLS_ECDSA_C=n   this fixes kconfig, but breaks compile of hostap
    
    #CONFIG_MBEDTLS_PSA_CRYPTO_C=y
    #CONFIG_MBEDTLS_USE_PSA_CRYPTO=y
    #CONFIG_PSA_CRYPTO_ENABLE_ALL=n
    CONFIG_PSA_WANT_RSA_KEY_SIZE_4096=y
    CONFIG_PSA_WANT_RSA_KEY_SIZE_2048=y
    
    #CONFIG_MBEDTLS_MAC_ALL_ENABLED=n
    #CONFIG_MBEDTLS_ECP_ALL_ENABLED=y  Failed, dont have some crypto implementations?
    #CONFIG_MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED=n
    #CONFIG_MBEDTLS_PK_C=y
    #CONFIG_MBEDTLS_PK_PARSE_C=y
    #CONFIG_MBEDTLS_PK_WRITE_C=y
    #CONFIG_MBEDTLS_PKCS5_C=y
    
    # save some flash by not having the PEM translate code (default is n)
    #CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=n
    
    # use CryptoCell backend not Oberon to avoid 0x3b00 error parsing certificates?
    #CONFIG_CC3XX_BACKEND=y
    #CONFIG_OBERON_BACKEND=n
    # Use PSA
    #CONFIG_MBEDTLS_LEGACY_CRYPTO_C=n

    Any comments or hints welcome, maybe this will help someone else. My way forward now is to create a "IOT device" specific web url on my server with a self-signed certif (RSA 2048) and hope that will work. 

  • Well, depends which of the suggestions you mean?

    CONFIG_MBEDTLS_MPI_MAX_SIZE=512

    - my build already has this as the default (maybe due to NCS 2.8?)

    CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
    CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=16384

    CONFIG_NET_SOCKETS_TLS_SET_MAX_FRAGMENT_LENGTH=n

    - again, already set to these values by default apparently

    Also, it doesn't seem that the issue in that post is in fact resolved anyway?

Related