What is the best way to securely store TLS credentials on my nRF9151 outside of the modem flash, on persistent (ideally overwrite protected) non volatile flash?

Issue:

There seem to be plenty of ways to securely store TLS credentials (generated off the device), or any sort of string data, in persistent storage on an nRF91x device. I would like to know what the recommended and simplest approach is to do this for my application. 

We are using an Ethernet network interface along with the nRF9151 internal LTE modem, to communicate with an AWS IoT MQTT broker. I have found out that credentials stored on the modem flash are NOT accessible to the application core, and trying to use AT commands to read these credentials does not work (which makes sense, that would be a big security vulnerability).

I would like to use the same credentials for both the Ethernet and LTE interfaces, and thus it appears I will have to store a copy of the credentials somewhere outside of the modem flash. Ideally I want to use the simplest and most NCS / Zephyr idomatic way to do this, while keeping code bloat from added libraries as small as possible. 


What I've done:


I have tried to use the PSA Protected storage library, , following this sample code, but it seems like the keys are too large. The sample works fine on my nRF9151DK board out-of-the-box, but when I replace the test strings with my key, the program crashes only only console logs the boot header. The TF-M PSA Protected Storage README mentions that the PS_MAX_ASSET_SIZE value is how to set the size of a value in the PSA, but I have tried to use CONFIG_PSA_ASSET_SIZE=2048, and it appears this Kconfig symbol does not exist.

psa_protected_storage/prj.conf:10: warning: attempt to assign the value '2048' to the undefined symbol PS_MAX_ASSET_SIZE

I've also looked over the PSA_crypto sample, although that appears to be for handling cyptography and device cert signing, rather than just key-value persistent storage of private data. 

I've also read the Key storage in the nRF Connect SDK docs, and they mendion using the PSA crypto API, but I am not sure this is what I am looking for, or if this is the best approach to accomplish this. 

Given psa_import_key() fxn seems to import a key in binary format, I am not sure the *.pem type certs would work with this. 


I was thinking I could potentially create a seperate 'credential flashing' application, which will run at the factory when device firmware is initally flashed and modem firmware is updated, and put the keys in a seperate  directory and source file (like the zephyr aws iot mqtt sample seems to do), and then run the 'credential flashing' application to take those keys and write them to  device persistent storage. 

It seems like however I get the keys stored on the device securely, at the beginning of the devices life I can use the tls_credentials lib to pull the keys into RAM and assign a security tag to them, allowing me to configure the mqtt clients tls config struct accordingly. As a reference this is the fxn used in the zephyr aws iot mqtt sample:

static int setup_credentials(void)
{
	int ret;

	ret = tls_credential_add(TLS_TAG_DEVICE_CERTIFICATE, TLS_CREDENTIAL_SERVER_CERTIFICATE,
				 public_cert, public_cert_len);
	if (ret < 0) {
		LOG_ERR("Failed to add device certificate: %d", ret);
		goto exit;
	}

	ret = tls_credential_add(TLS_TAG_DEVICE_PRIVATE_KEY, TLS_CREDENTIAL_PRIVATE_KEY,
				 private_key, private_key_len);
	if (ret < 0) {
		LOG_ERR("Failed to add device private key: %d", ret);
		goto exit;
	}

	ret = tls_credential_add(TLS_TAG_AWS_CA_CERTIFICATE, TLS_CREDENTIAL_CA_CERTIFICATE, ca_cert,
				 ca_cert_len);
	if (ret < 0) {
		LOG_ERR("Failed to add device private key: %d", ret);
		goto exit;
	}

exit:
	return ret;
}

It seems like its 'left to the reader' to figure out how to place the credentials in secure persistent memory / non volatile flash, but however its done, the above approach should allow me to use  them with an mqtt client. 

Also for reference, I have been following the nRF AWS IoT docs on credential generation (nRF91: Keys generated by AWS), and this has worked fine so far with LTE (because the credentials are then flashed to modem firmware using the nrfcredstore cli utility - but these are not accessible to the application core code).


Dev setup:

OS: Linux Ubuntu 24.04.1

Board: nrf9151DK HW v0.9.0 , AND our custom board built around the nRF9151 SiP 

SDK:  nRF Connect SDK V3.1.0 


All advice, support, and feedback is greatly appreciated!

Thank you Devzone team :) 

  • Hi,

    I am sorry for the delay. We have looked into this but we are not sure we understand your use case. You write you want hardcoded credentials, but so I am not misunderstanding, do you mean in code (which could then be a #define if accessible in non-secure was OK), or device specific keys?

    I need to look further into the problem with TFM credentials and modem lib together. Other than that, increaseing the TF-M PS maximum asset size requiers other configs to be increased (see this post):

    • CONFIG_TFM_PS_MAX_ASSET_SIZE
    • CONFIG_TFM_CRYPTO_IOVEC_BUFFER_SIZE
    • CONFIG_TFM_ITS_BUF_SIZE
  • Hello Einar,


    I am not sure how to explain what I need better. To summarize, I simply need to store TLS credentials somewhere securely on the device, and retrieve them on device startup and place them in RAM using the tls_credentials api. It seems like the PSA PS lib is not able to be used (cannot be enabled in Kconfig) while TF-M is enabled, but I must have TF-M enabled so that I can use the on-chip LTE modem with the NCS modem lib. 

    I DO NOT want to store the credentials in source code / hardcoded, although I have (for our in house development) given the PSA PS library is not an option. I see this as a massive security vulnerability, which is why I am looking for a way to store the credentials somewhere they are secure, not in plain text, and in a static partition that will not be overwritten by DFU.

    Thank you for sharing that post - I will keep in mind the maximum asset size limitations as we move forward.

    Please let me know when you are able to find out more about issues with using TF-M and PSA PS lib together in the same application. That being said, I am not set on specifically using the PSA PS library, rather I just want some way to store the TLS credentials I need securely in persistent storage on my device, so that at device startup, I can fetch them and load them into RAM using the tls_credentials api and the function I shared above. This should allow them to be used by the networking stack code if I recall correctly. 

    Thank you very much for your help.

  • Hi,

    I fully agree that hardcoded credentials is a bad choice, so please to not take my question and comment about that as a generic suggestion.

    We are stil looking into using TF-M PS for TLS credentials while the modem lib is enbled though, and I will get back to you on that.

  • Hi,

    I am sorry for the delay. This should work with the modem lib if you set CONFIG_NET_SOCKETS_OFFLOAD=n.

  • Thanks for the response Einar, although unfortunately we cannot do this. As first outlined in my post we must have offloading enabled in order to use the nrf modem lib (so that we can use BOTH LTE and Ethernet in a single compiled application).

    Please let me know if you or the team have discovered any other solutions to this issue. 

    Thank you. 

Related