How to set identity key in tfm configuration?

As per my understanding, identity key can be set using idenitytKey library.

But as the documentation says, " TF-M has access to the identity key using internal APIs and does not need to use this library."

I would like to know how to set identitykey in TFM configuration?

Parents
  • Hi,

    Please see the Provisioning image which demonstrate how to provision a device with an identity key.

  • Hi,

    The use case I am trying to work here is that I have a secure API in TFM mode that imports key using psa_key_import()

    The prj.conf file has below configs:

    # TFM config
    CONFIG_BUILD_WITH_TFM=y
    CONFIG_TFM_PROFILE_TYPE_NOT_SET=y
    CONFIG_TFM_IPC=y

    # PSA crypto config
    CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y
    CONFIG_PSA_CRYPTO_DRIVER_OBERON=n

    # Increased TFM partition size from 0x50000(Default) to 0x60000
    CONFIG_PM_PARTITION_SIZE_TFM=0x60000

    # Increased max number of assets that can be used for persistance storage
    CONFIG_TFM_ITS_NUM_ASSETS_OVERRIDE=y
    CONFIG_TFM_ITS_NUM_ASSETS=32

    # Increasing size of stack, required for KPA
    CONFIG_MAIN_STACK_SIZE=2048

    Now from this secure API I want to call identity_key_write_key() API. I am unable to call this API successfully. When I enable CONFIG_IDENTITY_KEY, it has dependency to disable config CONFIG_BUILD_WITH_TFM. But that is needed for my implementation where I am using TFM for security.

    I referred to the  Provisioning image  sample but it does not have TFM configs.

    As I stated above, in the idenitytKey library documentation it is written that  " TF-M has access to the identity key using internal APIs and does not need to use this library."


    Is it so that with CONFIG_BUILD_WITH_TFM configuration, 
    CONFIG_IDENTITY_KEY config cannot be used?

  • Hi,

    skirti said:
    I referred to the  Provisioning image  sample but it does not have TFM configs.

    You are right that the provisioning image does not include TF-M. The idea is to use that first (during provisioning), and that will write keys to the KMU (UICR). Then these are accessed subsequently by the firmware running TF-M.

    skirti said:
    Is it so that with CONFIG_BUILD_WITH_TFM configuration, CONFIG_IDENTITY_KEY config cannot be used?

    Yes. Is it so that you want to write the identity key from your non-secure application while using TF-M? If so, that will not work directly, as the KMU and UICR is only accessible from secure mode. When using TF-M (or using a non-secure application in any way), you cannot do this from y our application. So if you want to do that for some reason, you would have to do this from TF-M. And if you would like to initiate it from the non-secure application you would have to make a secure sevice in TF-M that is accessible to the application. You can see an example of that in TF-M secure peripheral partition. This also use a HW peripheral, but you can ignore that part. Remember that TF-M is not a Zephyr application, so configuration etc is done differently.

    I do not have a full understanding of your goal so I cannot say if this approach makes sense in your case, though. It could make sense to back-track a bit to look at the end goals / what you really want to achieve, and then consider how this can be achieved in the best manner.

  • Hello, 
    Thanks for the explanation.

    Sharing complete scenarios for clarity on end goal.

    connectSDK version used: 2.1.0
    Development Board used: nrf5340
    Build command used: west build --build-dir ./build ./ --pristine --board nrf5340dk_nrf5340_cpuapp_ns

    We have build a nonsecure app which call the secure APIs.
    We have a secure API to provision the device and a few secure APIs to perform crypto operations using provisioned keys.
    These APIs we have implemented using TFM secure services.

    The provisioning API takes keys to provision as input. From secure Provisioning API we call psa_import_key() with a specific key_id.
    From other secure APIs we do crypto operations with the specific key_ids that are already provisioned. 

    The prj.conf file looks like below:

    # TFM config
    CONFIG_BUILD_WITH_TFM=y
    CONFIG_TFM_PROFILE_TYPE_NOT_SET=y
    CONFIG_TFM_IPC=y
    
    # PSA crypto config
    CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y
    CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
    
    # Increased TFM partition size from 0x50000(Default) to 0x60000
    CONFIG_PM_PARTITION_SIZE_TFM=0x60000
    
    # Increased max number of assets that can be used for persistence storage
    CONFIG_TFM_ITS_NUM_ASSETS_OVERRIDE=y
    CONFIG_TFM_ITS_NUM_ASSETS=32 
    

    This all implementation works fine.

    Problem:

    Now we want to add attestation process.
    We know that we have to use IdentityKey library API identity_key_write_key() 
    to set the attestation key and psa_initial_attest_get_token() to use it but as discussed before config CONFIG_BUILD_WITH_TFM is conflicting with CONFIG_IDENTITY_KEY. 

    Would you please suggest what would be better approach?

     

  • Hi,

    I see. This is the use case for which we have the provisioning image. This provisioning is a one time operation that you typically do in production, and due to the (deliberate) limitation that you can only write to the KMU from secure mode (with the added benefit that you don't include unnecessary code in the application code), we provide the provisioning image as a sample of an image you can run on the device during production to do provisioning, before you program the application firmware that will be used in the field. What is the reason this approach does not work for you?

    If you want to do this from the firmware that will run on the devices in the field, you need to address the problem that this must be done form TF-M (secure), as it cannot be done from your non-secure application. So if you really want to this the way I think you describe, you need to do as I suggest in my previous post and call identity_key_write_key() etc. from TF-M, in you custom secure service. There is absolutely no way you can do this from your non-secure application.

Reply
  • Hi,

    I see. This is the use case for which we have the provisioning image. This provisioning is a one time operation that you typically do in production, and due to the (deliberate) limitation that you can only write to the KMU from secure mode (with the added benefit that you don't include unnecessary code in the application code), we provide the provisioning image as a sample of an image you can run on the device during production to do provisioning, before you program the application firmware that will be used in the field. What is the reason this approach does not work for you?

    If you want to do this from the firmware that will run on the devices in the field, you need to address the problem that this must be done form TF-M (secure), as it cannot be done from your non-secure application. So if you really want to this the way I think you describe, you need to do as I suggest in my previous post and call identity_key_write_key() etc. from TF-M, in you custom secure service. There is absolutely no way you can do this from your non-secure application.

Children
  • Hello,

    Thanks for the quick response.

    We are not calling identity_key_write_key() from nonsecure directly. Below is the sequence of calls:
    1. From nonsecure App -> Call Provisioning API
    2. Custom TFM secure services are implemented 
    3. Call goes to secure Provisioning API -> Here trying to call identity_key_write_key() API <PROBLEM>

    Building with below command:
    west build --build-dir ./build ./ --pristine --board nrf5340dk_nrf5340_cpuapp_ns

    prj.conf: at path(project root directory)

    # TFM config
    CONFIG_BUILD_WITH_TFM=y
    CONFIG_TFM_PROFILE_TYPE_NOT_SET=y
    CONFIG_TFM_IPC=y
    
    # PSA crypto config
    CONFIG_PSA_CRYPTO_DRIVER_CC3XX=y
    CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
    
    # Increased TFM partition size from 0x50000(Default) to 0x60000
    CONFIG_PM_PARTITION_SIZE_TFM=0x60000
    
    # Increased max number of assets that can be used for persistence storage
    CONFIG_TFM_ITS_NUM_ASSETS_OVERRIDE=y
    CONFIG_TFM_ITS_NUM_ASSETS=32 

     As per our understanding, config CONFIG_BUILD_WITH_TFM instructs the Zephyr build process to additionally generate a TF-M image for the Secure Execution environment, along with the Zephyr image. Finally we get a merged.hex which has both TF-M image and Zephyr image, that we are using to flash the device.

    So, here the call to identity_key_write_key() is from a secure API implemented through TFM custom secure services.
    So I did not understand, are you suggesting something different that I missed?
    Or there is some other build method that we should follow?

  • Hi,

    skirti said:
     As per our understanding, config CONFIG_BUILD_WITH_TFM instructs the Zephyr build process to additionally generate a TF-M image for the Secure Execution environment, along with the Zephyr image. Finally we get a merged.hex which has both TF-M image and Zephyr image, that we are using to flash the device.

    That is correct.

    skirti said:
    So, here the call to identity_key_write_key() is from a secure API implemented through TFM custom secure services.

    Not unless you have added a secure service that does this? The library we provide (and use in the provisioning sample) is designed to run in secure code, and we do not provide any secure service for calling this via TF-M.

    skirti said:
    So I did not understand, are you suggesting something different that I missed?

    I think so. We do not have any code for doing provisioning via TF-M. The way we intended for this to be done, and what we recomend, is to do provisioning as you see in the provisioning image sample, that goes hand in hand with the TF-M: PSA template. The latter use TF-M, but not the former.

    skirti said:
    Or there is some other build method that we should follow?

    What you are describing is not supports out of the box. So if you really want to support doing provisioning while using TF-M (and not before), you must add support for it like I have outlined briefly before, by making a secure service that does it (essentially exposing identity_key_write_key or a similar function) to the non-secure application via a secure service implemented in TF-M.

  • Okay, understood. Thanks. So we will add secure service for calling identity_key API via TF-M.

    But how we will overcome the configuration issue.
    As said before, when I add config CONFIG_IDENTITY_KEY in prj.conf it conflicts with CONFIG_BUILD_WITH_TFM.

  • You cannot overcome it. When you use CONFIG_BUILD_WITH_TFM that means your application must be non-secure, and the KMU (which you need access to in order to use CONFIG_IDENTITY_KEY) is only accessible from secure-mode. That is why that needs to be doen in TF-M if you want to do it like this (though the recommendation is to use a separate binary to do provisioning before you program your application).

    So in other words, using CONFIG_IDENTITY_KEY with your non-secure application cannot and will not work. (And to use this library or another way to access the KMU to write the identity key from TF-M you also cannot use this config with TF-M, as this is a Zephyr configuration, and TF-M is not a Zephyr application).

  • Okay understood.

    Would like to confirm one more point.
    I was able to call API nrf_cc3xx_platform_identity_key_store(NRF_KMU_SLOT_KIDENT, <key>) to save the key and use psa_initial_attest_get_token() with the saved key.

    With this I need not to enable any config. Saw below in ./nrfxlib/nrf_security/tfm/CMakeLists.txt file:
    # Platform cannot be selected when building for TF-M, because TF-M itself has
    # control of the CryptoCell. Therefore, specifically for building TF-M we
    # enable it manually.
    set(CONFIG_NRF_CC3XX_PLATFORM True)

    As per my understanding due to availability of this API in TFM we are able to call nrf_cc3xx_platform_identity_key_store() from a custom secure service.

    Do you see any security risk in this approach?

Related