Skip to content

[fuse_ctrl] Zeroization#518

Merged
ekarabu merged 30 commits intomainfrom
lowrisc_ocp_zeroization
Sep 1, 2025
Merged

[fuse_ctrl] Zeroization#518
ekarabu merged 30 commits intomainfrom
lowrisc_ocp_zeroization

Conversation

@andrea-caforio
Copy link
Contributor

This is a functional (smoke tests not included) draft PR of the zeroization mechanism.

Open questions:

  1. The digest field of a partition is used to indicate whether a partition is in a zeroized state by
    counting the number of set bits in its bit representation. This has the side effect that ECC must
    be disabled for all digest fields since they are now read first upon initialization. If this is
    undesirable, we need to revert back to a separate zeroization field.
  2. The new OTP_CTRL_DAI_ZER_READ (verification of zeroization) can now read the entire
    address space of a partition. This is unproblematic for software partitions but for hardware partition it
    will return the scrambled data of secret partitions. If this is undesirable, a mechanism needs to
    be added to only allow reads of zeroized fuses. For example:
    • Flop address of most recent zeroized fuse and only allow accesses to this address.
    • Check in hardware whether fuse is zeroized and do not return in the negative case.
  3. There is a potential race condition that can occur during zeroization of a buffered
    partition when it is interrupted by a periodical consistency check. These checks are
    currently only disabled after a reset (when zeroization is detected).
    • Transfer the partition into a terminal FSM state upon the first successful OTP_CTRL_DAI_ZER_WRITE
      command?

@andrea-caforio andrea-caforio self-assigned this Jun 9, 2025
Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

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

Thanks for the PR @andrea-caforio ! I did a first pass and left some comments. Specifically to your questions:

  1. The digest field of a partition is used to indicate whether a partition is in a zeroized state by counting the number of set bits in its bit representation. This has the side effect that ECC must be disabled for all digest fields since they are now read first upon initialization. If this is undesirable, we need to revert back to a separate zeroization field.

I don't think we should ignore ECC bits on the digest unless it's zeroized. Can we instead do the following procedure?

  1. Read the digest with ECC disabled to check if the partition is zeroized.
  2. If it's not, read the entire partition and at the end the digest including ECC (as in the existing implementation)?
  1. The new OTP_CTRL_DAI_ZER_READ (verification of zeroization) can now read the entire address space of a partition. ...

I left a comment directly in the code regarding how this could be addressed.

  1. There is a potential race condition that can occur during zeroization of a buffered partition when it is interrupted by a periodical consistency check. These checks are currently only disabled after a reset (when zeroization is detected).
    • Transfer the partition into a terminal FSM state upon the first successful OTP_CTRL_DAI_ZER_WRITE command?

The specification discusses a similar issue related to the life cycle partition and life cycle state updates. The challenge here is that at the point where the is zeroization started by the first DAI command and between the last zeroization write (or the reset to trigger re-reading the zeroized digest).

I think it could be solved by adding a mubi register that is written upon detecting a zeroized digest or the first zeroize write (whatever comes first) which is then used to ignore all integrity and consistency check requests. For my own understanding: the integrity checks can proceed as long as the zeroization isn't finished yet, right (because they operate exclusively on the buffer)?

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch from a631755 to d3e74d4 Compare June 18, 2025 18:26
@andrea-caforio
Copy link
Contributor Author

Thank you @vogelpi for the thorough review. The PR is ready for a second round. :-)

@andrea-caforio andrea-caforio marked this pull request as ready for review June 19, 2025 15:23
@andrea-caforio
Copy link
Contributor Author

Concerning the race condition. The first successful zeroization request to a partition will periodic consistency check for this partition.

Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

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

Thanks @andrea-caforio , I am not done yet and will continue with the review later.

Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

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

Some more comments but still not finished. Will continue later.

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch from d3e74d4 to d44c072 Compare June 26, 2025 05:57
@andrea-caforio
Copy link
Contributor Author

@vogelpi Thanks for the 2nd-round of review. With the exception of one point (see comment), I hope everything else
is addressed.

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch from d44c072 to 2266797 Compare June 27, 2025 11:46
Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

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

Thanks @andrea-caforio for the updates. I have some questions remaining. This is looking good.

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch from 2266797 to d8abd98 Compare July 4, 2025 06:20
Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

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

Thanks @andrea-caforio for addressing the remaining comments. This LGTM!

As discussed over email, we should add a separate field per partition to mark them as zeroized rather than using the digest (to avoid collisions - especially when defining a non-zero margin). But this can be done as a separate PR in my view.

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch 3 times, most recently from 98c47eb to d75877d Compare July 9, 2025 16:55
@elliotb-lowrisc
Copy link

I'm a bit concerned about the use of $countones(otp_rdata_i).

I suspect $countones may not be synthesisable in all tools. It seems Vivado supports it, but I'm not sure about others. Might I suggest something like the following (untested) 'loop':

logic [$bits(ScrmblBlockWidth)-1:0] count;

count = 0;
for (int ii = 0 ; ii < ScrmblBlockWidth ; ii++) begin
  count = count + otp_rdata_i[ii];
end

Hopefully this will be synthesised as a tree of adders. First adding 32 pairs of single bits, then adding 16 pairs of those two-bit partial sums, 8 pairs of three-bit part-sums, 4 pairs of four-bit part-sums, 2 pairs of five-bit part-sums, and a final add of a pair of 6-bit part-sums to reach the final single result.

Such a large adder tree may unfortunately take up a sizable bit of chip area and path delay.

If you are simply checking that all bits are set (as currently seems to be the case) then it would be far better to use a reduction AND operation: &otp_rdata_i

Another way to reduce the chip area could be to split the 'countones' adder-tree into a separate module and only instantiate one that is shared by all partitions somehow. You may be able to optimise this further by turning it into a multi-cycle operation and greatly reducing the size of the adder tree.

There may also be more efficient ways to synthesise $countones than what I can currently think up.

@matutem
Copy link

matutem commented Jul 24, 2025

@elliotb-lowrisc The logarithmic $countones you describe should work, may be required given #579. The largest number of adders are quite small so it may not be that terrible. We could also stop adding at some level, for example given the counts for 16-bit chunks, and decide on that partial information. For example, and based on #579, we could flag "fatal" if more than one has a count of 2, and "okay" if none has more than 1.

@elliotb-lowrisc
Copy link

@matutem Ah, I had missed that the zeroization test logic had moved from being in each partition to being a single instance in the DAI. The impact on chip area shouldn't be nearly as bad as I previously thought. $countones support in synthesis tools remains a question for me. I'd personally choose to avoid it just in case, but it can be left as-is and changed later if it does turn out to be an issue or to improve area a bit.

@elliotb-lowrisc
Copy link

Or was I still mistaken? Perhaps it is in both the DAI and each partition. My apologies. I am still concerned about the chip area impact then.

Copy link

@elliotb-lowrisc elliotb-lowrisc left a comment

Choose a reason for hiding this comment

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

I've not yet fully come to grips with these changes (or OTP in general), but I have found a few things I hope will be useful to point out.

@andrea-caforio andrea-caforio force-pushed the lowrisc_ocp_zeroization branch from af0ddbd to 5acaca7 Compare July 28, 2025 14:31
andrea-caforio and others added 11 commits August 29, 2025 08:14
Upon the first successful zeroization request to a partition,
all further consistency checks will not execute anymore.

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
* [fuse_ctrl, rtl] Zeroization fuse

Use a dedicated zeroization field instead of the digest
as the zeroization marker. The field is inserted after
the digest when a partition is labelled as zeroizable.

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

* [fuse_ctrl, doc] Zeroization programmer's guide

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

* [fuse_ctrl, mmap] Ratchet seed partitions (#627)

* [fuse_ctrl, mmap] Add ratchet seed partitions

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

* [OCP LOCK] Add FC Ratchet Seed Memory Map.

The Fuse Controller memory map is updated to include a reference
implementation of the OCP L.O.C.K Hard Epoch Key (HEK) ratchet seeds.

Each ratchet seed is 256-bits, and is stored in a software partition to
make it accessible to MCU or Core firmware. The seed is wrapped by an
obfuscation key, making it safe to be read from the MCU.

Each ratchet seed is stored in a separate fuse partition to provide the
following properties:

* Write locking: At fuse programming time by writing a non-zero value to
  the partition's digest field. The digest is written to fuses.
* Read locking: By write-lockable CSR. The lock is held until the next
  SS reset.
* Zeroization: Managed by software.

The partitions are placed at the end of the memory map to allow
integrators to remove the partition when OCP L.O.C.K functionality is
not required.

The naming convention uses the partition name as the prefix for each
ratchet seed. This is to also make the autogeneration of digest and
zeroization fields more ergonomic for firmware - e.g.
`CPTRA_SS_LOCK_HEK_PROD_0_DIGEST` corresponds to the digest field for
the `CPTRA_SS_LOCK_HEK_PROD_0` partition.

Signed-off-by: Miguel Osorio <miguelosorio@google.com>
(cherry picked from commit 04d1160)

* [fuse_ctrl, rtl] Deassert token valid signal upon zeroization

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

* [fuse_ctrl, rtl] Remove obsolete zeroization logic

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

---------

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Miguel Osorio <miguelosorio@google.com>
Co-authored-by: Miguel Osorio <miguelosorio@google.com>

* [fuse_ctrl, doc] Zeroization hardware changes documentation

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>

---------

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Miguel Osorio <miguelosorio@google.com>
Co-authored-by: Miguel Osorio <miguelosorio@google.com>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Only ratchet seed partitions and the vendor secret partition
are zeroizable.

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
According to Emre, this is only needed for the partitions that contain
the Unique Device Secret (UDS) and field entropy (FE).

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
…zing

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
andrea-caforio and others added 12 commits September 1, 2025 01:08
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Co-authored-by: Andreas Kurth <adk@lowrisc.org>
…ck_token`

Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
Signed-off-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andreas Kurth <adk@lowrisc.org>
Signed-off-by: Andrea Caforio <andrea.caforio@lowrisc.org>
…dated timestamp and hash after successful run
ekarabu
ekarabu previously approved these changes Sep 1, 2025
…dated timestamp and hash after successful run
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.

8 participants