Skip to content

[perso] Remove CDI 0 and CDI 1 generation and endorsement during provisioning - #31033

Merged
timothytrippel merged 3 commits into
lowRISC:earlgrey_1.0.0from
xorptr:perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1
Aug 26, 2026
Merged

[perso] Remove CDI 0 and CDI 1 generation and endorsement during provisioning#31033
timothytrippel merged 3 commits into
lowRISC:earlgrey_1.0.0from
xorptr:perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1

Conversation

@xorptr

@xorptr xorptr commented Aug 17, 2026

Copy link
Copy Markdown

Based on changes in PR #31014, I observed that perso blob to and from host need to be live together during provisioning. This takes ~10KiB of space in SRAM (~5KiB for each blob object).

One approach to reduce the SRAM usage is to change the flow such that only one of those objects need to be live at a given time. Since the device firmware only uses perso blob to host in order to read the device endorsed certificates and write them to internal flash, one approach to achieve the goal is to have the host send back the device endorsed certificates and have the device firmware read them from blob send from host. Currently, the device endorsed certificates include: CWT UDS, CDI 0, and CDI 1.

@sasdf and @cfrantz suggested that we could remove CDI 0 and CDI 1 certificates from the provisioning flow since ROM_EXT is supposed to re-generate them during boot. After discussion with @timothytrippel, I decided to use this approach.

This PR makes changes to remove CDI 0 and CDI 1 generation from device firmware during the provisioning flow. The host now only expects UDS certificate and SKU extension specific certificates.

I also made changes to the CWT dice chain validation on the host side since the code currently expects at least 2 certs in the chain.

I also added minor change to add calls to sc_keymgr_sw_binding_unlock_wait where it seems appropriate during the provisioning flow

This PR does not actually split the perso blob to and from host yet (mentioned as the goal earlier in the description). I will make the changes to split them in a follow-up PR

@xorptr
xorptr requested review from a team and cfrantz as code owners August 17, 2026 20:43
@xorptr
xorptr requested review from pamaury and removed request for a team August 17, 2026 20:43
@xorptr
xorptr force-pushed the perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1 branch from 5f6f297 to cf8a61a Compare August 17, 2026 23:13

@cfrantz cfrantz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to determine if this change has any impact on the ot-provisioning infrastructure.

@xorptr
xorptr force-pushed the perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1 branch from cf8a61a to f2874f8 Compare August 20, 2026 23:54
@timothytrippel

Copy link
Copy Markdown
Contributor

please rebase to fix CI

@xorptr
xorptr force-pushed the perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1 branch from f2874f8 to a3aef4e Compare August 25, 2026 17:49
@xorptr

xorptr commented Aug 25, 2026

Copy link
Copy Markdown
Author

Rebased on top of last commit in #31014 (08210ebf42f34b20529e76d184642ae1ea607a1e)

@xorptr
xorptr force-pushed the perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1 branch from a3aef4e to 5e3273b Compare August 26, 2026 10:58
xorptr added 3 commits August 26, 2026 10:23
…itionals

Putting statement for single line conditionals in curly braces so that
someone is less likely to make a mistake when new statements are added

Signed-off-by: Lovepreet Singh <lpsingh@google.com>
…provisioning

This commit changes perso firmware code to NOT generate CDI_0 and CDI_1
certificates during provisioning flow. The current behavior is as
follows:

1. Device generates
   [CDI_0](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L655-L656)
   and [CDI_1](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L675-L677)
   endorsed certificates with zeroed out digest value and sends them to
   the host along with the generated UDS TBS certificate

2. Host uses these endorsed certificates to [compute the hash](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/host/provisioning/ft_lib/src/lib.rs#L419-L422)
   of the data that device is expected to write to the flash

3. Host DOES NOT send endorsed CDI_0 and CDI_1 certificates back to the
   device. Host does send endorsed UDS certificate (see
   [code](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/host/provisioning/ft_lib/src/lib.rs#L381))

4. Device reads endorsed UDS certificate sent by the host for X.509, or
   from blob sent to the host for CWT. Device reads endorsed CDI_0 and
   CDI_1 certificates from blob sent to the host (see
   [code](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L990-L1016))

5. Device writes endorsed UDS certificate to FACTORY page, and endorsed
   CDI_0 and CDI_1 certificates to DICE page (see
   [code](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L1059-L1084))

6. Device [reads and hashes endorsed UDS, CDI_0, and CDI_1
   certificates](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L502-L537)
   along with other data, and [sends them to the
   host](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/manuf/base/ft_personalize.c#L1230-L1231)

7. Host checks the device hash against the hash it expects (see
   [code](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/host/provisioning/ft_lib/src/lib.rs#L453-L475))

The new behavior is as follows:

1. Device only generates UDS TBS certificate for DICE chain and sends it
   to the host for endorsement

2. Host only takes into account endorsed UDS certificate (for the DICE
   chain) when computing the hash it expects later

3. Host sends endorsed UDS certificate back to the device

4. Device reads endorsed UDS certificate sent by the host for X.509, or
   from the blob sent to the host for CWT.

5. Device only writes endorsed UDS certificate (for the DICE chain) to
   FACTORY page

6. Device computed hash only includes endorsed UDS certificate (for the
   DICE chain). Device sends the computed hash to the host

7. Host checks the hash sent by the device against the hash it expects

NOTES:
1. I have still kept the "DICE" page marked as "used" in the flash
layout list since I am not sure if the extensions look for the first
unused page to determine pages that are available to them

2. I changed the logic to validate the DICE CWT chain since [it needs at
   least 2
   certificates](https://android.googlesource.com/platform/tools/security/+/d80118316fb3b87092d4128196884b11fa19e08c/remote_provisioning/hwtrust/src/cbor/dice/chain.rs#109).
   This has a side effect that the generated UDS certificate will not be
   checked for valid form since it is not parsed
   [earlier](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/host/provisioning/ft_lib/src/lib.rs#L416-L418)
   as well

Tested by running
`//sw/host/provisioning/orchestrator/tests:e2e_emulation_dice_cwt_cw340_test`,
`//sw/host/provisioning/orchestrator/tests:e2e_emulation_dice_mldsa_cw340_test`
`//sw/host/provisioning/orchestrator/tests:e2e_emulation_cw340_test`,
and `//sw/host/provisioning/orchestrator/tests:e2e_multistage_emulation_tpm_cw340_test`
targets locally

Signed-off-by: Lovepreet Singh <lpsingh@google.com>
…iate locations

The [documentation](https://github.com/lowRISC/opentitan/blob/9d35c96fc0728d82fcc0a0e1ffa06ab532dbe448/sw/device/silicon_creator/lib/drivers/keymgr.h#L111-L134)
for keymgr functions mention that call to `sc_keymgr_sw_binding_unlock_wait` is
recommended after calls to `sc_keymgr_sw_binding_set` or
`sc_keymgr_advance_state`. This commit adds calls to
`sc_keymgr_sw_binding_unlock_wait` at appropriate locations in
`sw/device/silicon_creator/manuf/base/ft_personalize.c` as per that
documentation

Tested by running
`//sw/host/provisioning/orchestrator/tests:e2e_emulation_dice_mldsa_cw340_test`,
and  `//sw/host/provisioning/orchestrator/tests:e2e_emulation_cw340_test`
targets locally

Signed-off-by: Lovepreet Singh <lpsingh@google.com>
@xorptr
xorptr force-pushed the perso_ft_provisioning_reduce_sram_usage_remove_cdi0_and_cdi1 branch from 5e3273b to f12f9cd Compare August 26, 2026 17:24
@timothytrippel
timothytrippel merged commit 37524d2 into lowRISC:earlgrey_1.0.0 Aug 26, 2026
93 of 101 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants