Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions hw/ip/keymgr_dpe/data/keymgr_dpe.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,29 @@
act: "req",
package: "kmac_pkg", // Origin package (only needs for the requester)
},
{ struct: "otp_keymgr_key",
{ struct: "keymgr_dpe_creator_root_key",
type: "uni",
name: "otp_key",
name: "creator_root_key",
act: "rcv",
package: "otp_ctrl_pkg",
package: "keymgr_dpe_pkg",
},
{ struct: "otp_device_id",
{ struct: "keymgr_dpe_creator_seed",
type: "uni",
name: "otp_device_id",
name: "creator_seed",
act: "rcv",
package: "otp_ctrl_pkg",
package: "keymgr_dpe_pkg",
},
{ struct: "keymgr_dpe_owner_seed",
type: "uni",
name: "owner_seed",
act: "rcv",
package: "keymgr_dpe_pkg",
},
{ struct: "keymgr_dpe_device_id",
type: "uni",
name: "device_id",
act: "rcv",
package: "keymgr_dpe_pkg",
},
{ struct: "lc_tx",
type: "uni",
Expand Down
30 changes: 16 additions & 14 deletions hw/ip/keymgr_dpe/doc/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ Referring to the [Comportable guideline for peripheral device functionality](htt

## [Inter-Module Signals](https://opentitan.org/book/doc/contributing/hw/comportability/index.html#inter-signal-handling)

| Port Name | Package::Struct | Type | Act | Width | Description |
|:----------------|:-----------------------------|:--------|:------|--------:|:--------------|
| edn | edn_pkg::edn | req_rsp | req | 1 | |
| aes_key | keymgr_pkg::hw_key_req | uni | req | 1 | |
| kmac_key | keymgr_pkg::hw_key_req | uni | req | 1 | |
| otbn_key | keymgr_pkg::otbn_key_req | uni | req | 1 | |
| kmac_data | kmac_pkg::app | req_rsp | req | 1 | |
| otp_key | otp_ctrl_pkg::otp_keymgr_key | uni | rcv | 1 | |
| otp_device_id | otp_ctrl_pkg::otp_device_id | uni | rcv | 1 | |
| lc_keymgr_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| lc_keymgr_div | lc_ctrl_pkg::lc_keymgr_div | uni | rcv | 1 | |
| rom_digest | rom_ctrl_pkg::keymgr_data | uni | rcv | 2 | |
| kmac_en_masking | logic | uni | rcv | 1 | |
| tl | tlul_pkg::tl | req_rsp | rsp | 1 | |
| Port Name | Package::Struct | Type | Act | Width | Description |
|:-----------------|:--------------------------------------------|:--------|:------|--------:|:--------------|
| edn | edn_pkg::edn | req_rsp | req | 1 | |
| aes_key | keymgr_pkg::hw_key_req | uni | req | 1 | |
| kmac_key | keymgr_pkg::hw_key_req | uni | req | 1 | |
| otbn_key | keymgr_pkg::otbn_key_req | uni | req | 1 | |
| kmac_data | kmac_pkg::app | req_rsp | req | 1 | |
| creator_root_key | keymgr_dpe_pkg::keymgr_dpe_creator_root_key | uni | rcv | 1 | |
| creator_seed | keymgr_dpe_pkg::keymgr_dpe_creator_seed | uni | rcv | 1 | |
| owner_seed | keymgr_dpe_pkg::keymgr_dpe_owner_seed | uni | rcv | 1 | |
| device_id | keymgr_dpe_pkg::keymgr_dpe_device_id | uni | rcv | 1 | |
| lc_keymgr_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
| lc_keymgr_div | lc_ctrl_pkg::lc_keymgr_div | uni | rcv | 1 | |
| rom_digest | rom_ctrl_pkg::keymgr_data | uni | rcv | 2 | |
| kmac_en_masking | logic | uni | rcv | 1 | |
| tl | tlul_pkg::tl | req_rsp | rsp | 1 | |

## Interrupts

Expand Down
28 changes: 28 additions & 0 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_ctrl_if.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// An interface that should be bound into an instance of keymgr_dpe_ctrl (and can access RTL signals
// through upwards hierarchical references).
interface keymgr_dpe_ctrl_if (input clk_i, input rst_ni);
import uvm_pkg::*;

// Function to access the key of one slot via backdoor.
// Required to load the UDS after XORing with generated randomness.
function automatic keymgr_dpe_env_pkg::key_shares_t get_key_of_slot(int unsigned slot);
import keymgr_dpe_pkg::DpeNumSlots;

// Check that the slot index is in range. The key_slots_q array has length DpeNumSlots, which is
// a global parameter.
if (slot >= DpeNumSlots) begin
`uvm_error($sformatf("%m"),
$sformatf("Slot index out of range: index is %0d but DpeNumSlots is %0d",
slot, DpeNumSlots))
return '0;
end

// This is an upwards hierarchical reference through the keymgr_dpe_ctrl module (into an
// instance of which this interface is bound)
return keymgr_dpe_ctrl.key_slots_q[slot].key;
endfunction
endinterface
1 change: 1 addition & 0 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_env.core
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ filesets:
- lowrisc:ip:kmac_pkg
files:
- keymgr_dpe_env_pkg.sv
- keymgr_dpe_ctrl_if.sv
- keymgr_dpe_if.sv
- keymgr_dpe_env_cfg.sv: {is_include_file: true}
- keymgr_dpe_env_cov.sv: {is_include_file: true}
Expand Down
4 changes: 4 additions & 0 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_env.sv
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class keymgr_dpe_env extends cip_base_env #(
`uvm_fatal(`gfn, "failed to get keymgr_dpe_vif from uvm_config_db")
end
cfg.scb = scoreboard;
if (!uvm_config_db#(virtual keymgr_dpe_ctrl_if)::get(
this, "", "keymgr_dpe_ctrl_vif", cfg.keymgr_dpe_ctrl_vif)) begin
`uvm_fatal(get_full_name(), "Could not get keymgr_dpe_ctrl_vif from uvm_config_db.")
end
endfunction

function void connect_phase(uvm_phase phase);
Expand Down
3 changes: 3 additions & 0 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_env_cfg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class keymgr_dpe_env_cfg extends cip_base_env_cfg #(.RAL_T(keymgr_dpe_reg_block)

`uvm_object_new

// Interface that is bound into the keymgr_dpe_ctrl instance
virtual keymgr_dpe_ctrl_if keymgr_dpe_ctrl_vif;

virtual function void initialize();
list_of_alerts = keymgr_dpe_env_pkg::LIST_OF_ALERTS;
tl_intg_alert_name = "fatal_fault_err";
Expand Down
32 changes: 18 additions & 14 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ interface keymgr_dpe_if(input clk, input rst_n);
// it so that status is changed to SideLoadNotAvail, then we may set it to SideLoadAvail again
lc_ctrl_pkg::lc_tx_t keymgr_dpe_en;
lc_ctrl_pkg::lc_keymgr_div_t keymgr_dpe_div;
otp_ctrl_pkg::otp_device_id_t otp_device_id;
otp_ctrl_pkg::otp_keymgr_key_t otp_key;
keymgr_dpe_pkg::keymgr_dpe_device_id_t otp_device_id;
keymgr_dpe_pkg::keymgr_dpe_creator_root_key_t creator_root_key;
keymgr_dpe_pkg::keymgr_dpe_creator_seed_t creator_seed;
keymgr_dpe_pkg::keymgr_dpe_owner_seed_t owner_seed;
rom_ctrl_pkg::keymgr_data_t[NumRomDigestInputs-1:0] rom_digests;

keymgr_pkg::hw_key_req_t kmac_key;
Expand Down Expand Up @@ -106,33 +108,35 @@ interface keymgr_dpe_if(input clk, input rst_n);
task automatic init(bit rand_otp_key, bit invalid_otp_key);
// Keymgr_dpe only latches OTP key once, so this scb does not support change OTP key on the
// fly. Will write a direct sequence to cover otp key change on the fly.
otp_ctrl_pkg::otp_keymgr_key_t local_otp_key;
keymgr_dpe_pkg::keymgr_dpe_creator_root_key_t local_creator_root_key;

// async delay as these signals are from different clock domain
#($urandom_range(1000, 0) * 1ns);
keymgr_dpe_en = lc_ctrl_pkg::On;
keymgr_dpe_div = 64'h5CFBD765CE33F34E;
otp_device_id = 'hF0F0;
otp_key = otp_ctrl_pkg::OTP_KEYMGR_KEY_DEFAULT;
for (int i = 0; i < NumRomDigestInputs; ++i) begin
rom_digests[i].data = 256'hA20A046CF42E6EAC560A3F82BFA76285B5C1D4AEA7C915E49A32D1C89BE0F507;
rom_digests[i].valid = '1;
end
// Load the default value for all seed's
local_creator_root_key = keymgr_dpe_pkg::KEYMGR_DPE_CREATOR_ROOT_KEY_DEFAULT;
creator_seed = keymgr_dpe_pkg::KEYMGR_DPE_CREATOR_SEED_DEFAULT;
owner_seed = keymgr_dpe_pkg::KEYMGR_DPE_OWNER_SEED_DEFAULT;
// If requested randomize the creator_root_key
if (rand_otp_key) begin
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(local_otp_key,
local_otp_key.creator_root_key_share0_valid == 1;
local_otp_key.creator_root_key_share1_valid == 1;
!(local_otp_key.creator_root_key_share0 inside {0, '1});
!(local_otp_key.creator_root_key_share1 inside {0, '1});
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(local_creator_root_key,
local_creator_root_key.share0_valid == 1;
local_creator_root_key.share1_valid == 1;
!(local_creator_root_key.share0 inside {0, '1});
!(local_creator_root_key.share1 inside {0, '1});
, , msg_id)
end else begin
local_otp_key = otp_ctrl_pkg::OTP_KEYMGR_KEY_DEFAULT;
end
if (invalid_otp_key) begin
local_otp_key.creator_root_key_share0_valid = 0;
local_otp_key.creator_root_key_share1_valid = 0;
local_creator_root_key.share0_valid = 0;
local_creator_root_key.share1_valid = 0;
end
otp_key = local_otp_key;
creator_root_key = local_creator_root_key;
endtask

// reset local exp variables when reset is issued
Expand Down
70 changes: 53 additions & 17 deletions hw/ip/keymgr_dpe/dv/env/keymgr_dpe_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
bit is_kmac_rsp_err;
bit is_kmac_invalid_data;
bit is_sw_share_corrupted;
// Indicates if the UDS was fetched by the keymgr_dpe for the first time.
// The UDS needs to be xored with randomness to counter SCA, however the
// current dv environment cannot replicate this randomness. As a workaround
// the generated value (UDS xored with randomness) is loaded by a backdoor
// directly from the DUT.
bit load_uds_with_randomness;

// HW internal key, used for OP in current state
keymgr_dpe_env_pkg::keymgr_dpe_key_slot_t current_key_slot;
Expand Down Expand Up @@ -150,11 +156,14 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
virtual function void process_kmac_data_req(kmac_app_item item);
keymgr_dpe_pkg::keymgr_dpe_ops_e op = get_operation();
bit is_err;
bit invalid_hw_input;
bit invalid_op;
logic [keymgr_dpe_pkg::DpeBootStagesWidth-1:0] boot_stage =
current_internal_key[current_key_slot.src_slot].boot_stage;

`uvm_info(`gfn, $sformatf("process_kmac_data_req: for op %s in state %s",
op.name, current_state.name), UVM_MEDIUM)
`uvm_info(`gfn, $sformatf({"process_kmac_data_req: for op %s in state %s",
"with boot_stage set to %0d"},
op.name, current_state.name, boot_stage), UVM_MEDIUM)

if (!cfg.keymgr_dpe_vif.get_keymgr_dpe_en()) begin
compare_invalid_data(item.byte_data_q);
Expand All @@ -168,8 +177,11 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
keymgr_dpe_pkg::OpDpeAdvance: begin
// Invalid outputs and invalid operations should results in random data
// for message data.
is_err = get_hw_invalid_input() || get_invalid_op();
`uvm_info(`gfn, $sformatf("What is is_err: %d", is_err), UVM_MEDIUM)
invalid_hw_input = get_hw_invalid_input();
invalid_op = get_invalid_op();
is_err = invalid_hw_input || invalid_op;
`uvm_info(`gfn, $sformatf({"Invalid HW Input %0b || Invalid OP %0b",
" = is_err %0b"}, invalid_hw_input, invalid_op, is_err), UVM_MEDIUM)
case (current_state)
keymgr_dpe_pkg::StWorkDpeAvailable: begin
if(boot_stage == keymgr_dpe_pkg::BootStageCreator) begin
Expand Down Expand Up @@ -973,20 +985,26 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(

virtual function void latch_otp_key();
key_shares_t otp_key;
if (cfg.keymgr_dpe_vif.otp_key.creator_root_key_share0_valid &&
cfg.keymgr_dpe_vif.otp_key.creator_root_key_share1_valid) begin
otp_key = {cfg.keymgr_dpe_vif.otp_key.creator_root_key_share1,
cfg.keymgr_dpe_vif.otp_key.creator_root_key_share0};
if (cfg.keymgr_dpe_vif.creator_root_key.share0_valid &&
cfg.keymgr_dpe_vif.creator_root_key.share1_valid) begin
otp_key = {cfg.keymgr_dpe_vif.creator_root_key.share1,
cfg.keymgr_dpe_vif.creator_root_key.share0};
end else begin
if (cfg.en_cov) cov.invalid_hw_input_cg.sample(OtpRootKeyValidLow);
`uvm_info(`gfn, "otp_key valid is low", UVM_LOW)
end
current_internal_key[current_key_slot.dst_slot].valid = 1;
current_internal_key[current_key_slot.dst_slot].boot_stage = keymgr_dpe_pkg::BootStageCreator;
current_internal_key[current_key_slot.dst_slot].max_key_version = max_key_version;
// This call load the "true" UDS without the randomness present in the
// hw slot. The problem is that when this function is called (when writing
// the first time into the start register) the randomness in the hw slot
// is not yet generated.
// The current workaround is to backdoor load on the first advance call
// in the available state as the src_slot has the UDS loaded.
current_internal_key[current_key_slot.dst_slot].key = otp_key;
current_internal_key[current_key_slot.dst_slot].key_policy = '0;
current_internal_key[current_key_slot.dst_slot].key_policy.allow_child = 1;
current_internal_key[current_key_slot.dst_slot].key_policy =
keymgr_dpe_pkg::DEFAULT_UDS_POLICY;
`uvm_info(`gfn,
$sformatf("latch_otp_key: key %p",
current_internal_key[current_key_slot.dst_slot]
Expand All @@ -998,6 +1016,15 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
);
endfunction

// Directly access the slot which holds the UDS with the xored randmoness
// Otherwise the scorebord would need to manually replicate the randomness
// generation.
virtual function void backdoor_load_uds(int slot);

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.

I think it would be better to read the randomness input (via backdoor) and then compute the UDS in the DV code, instead of reading the randomized UDS in the key slot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I think so too. I have opened a issue to track this #30758 so we can continue with the integration.

`uvm_info(`gfn, "Load UDS with randomness via backdoor", UVM_MEDIUM)
current_internal_key[slot].key =
cfg.keymgr_dpe_ctrl_vif.get_key_of_slot(slot);
endfunction

virtual function bit [TL_DW-1:0] get_current_max_version(
keymgr_dpe_pkg::keymgr_dpe_exposed_working_state_e state = current_state);
// design change this to 0 if LC turns off keymgr_dpe.
Expand Down Expand Up @@ -1071,11 +1098,10 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
key_policy : current_internal_key[current_key_slot.src_slot].key_policy;
keymgr_dpe_pkg::keymgr_dpe_ops_e op = get_operation();
`uvm_info(`gfn,
$sformatf({"get_invalid_op: op %s current_state: %s, ",
"current_internal_key[%0d] = %p"},
op.name, current_state.name, current_key_slot.src_slot,
current_internal_key[current_key_slot.src_slot]),
UVM_MEDIUM)
$sformatf({"get_invalid_op: op %s current_state: %s, src: %0d dst: %0d",
"current_internal_key = %p"}, op.name, current_state.name,
current_key_slot.src_slot, current_key_slot.dst_slot,
current_internal_key[current_key_slot.src_slot]), UVM_MEDIUM)
case (current_state)
keymgr_dpe_pkg::StWorkDpeReset : begin
if (get_operation() != keymgr_dpe_pkg::OpDpeAdvance) begin
Expand Down Expand Up @@ -1122,6 +1148,13 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
"src_slot valid == 0 err"}, op.name, current_state.name), UVM_MEDIUM)
return 1;
end
// Workaround to load the UDS with the xored randomness into the
// correct internal slot. The first (successful) advance call will
// use the UDS per default.
if (load_uds_with_randomness == 1'b0) begin
load_uds_with_randomness = 1'b1;
backdoor_load_uds(current_key_slot.src_slot);
end
return 0;
end
keymgr_dpe_pkg::OpDpeGenSwOut, keymgr_dpe_pkg::OpDpeGenHwOut: begin
Expand Down Expand Up @@ -1272,9 +1305,11 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
adv_creator_data_t exp, act;
string str = $sformatf("src_slot: %0d\n", current_key_slot.src_slot);

`uvm_info(`gfn, $sformatf("Compare data for boot stage 0"), UVM_MEDIUM)

if (exp_match) `DV_CHECK_EQ(byte_data_q.size, keymgr_dpe_pkg::DpeAdvDataWidth / 8)
act = {<<8{byte_data_q}};
exp.DiversificationKey = cfg.keymgr_dpe_vif.otp_key.creator_seed;
exp.DiversificationKey = cfg.keymgr_dpe_vif.creator_seed.seed;

for (int i = 0; i < keymgr_dpe_reg_pkg::NumRomDigestInputs; ++i) begin
exp.RomDigests[i] = cfg.keymgr_dpe_vif.rom_digests[i].data;
Expand Down Expand Up @@ -1310,7 +1345,7 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
string str = $sformatf("src_slot: %0d\n", current_key_slot.src_slot);

act = {<<8{byte_data_q}};
exp.OwnerRootSecret = cfg.keymgr_dpe_vif.otp_key.owner_seed;
exp.OwnerRootSecret = cfg.keymgr_dpe_vif.owner_seed.seed;
get_sw_binding_mirrored_value(exp.SoftwareBinding);

`CREATE_CMP_STR(unused)
Expand Down Expand Up @@ -1527,6 +1562,7 @@ class keymgr_dpe_scoreboard extends cip_base_scoreboard #(
is_kmac_rsp_err = 0;
is_kmac_invalid_data = 0;
is_sw_share_corrupted = 0;
load_uds_with_randomness = 0;
req_fifo.flush();
rsp_fifo.flush();
foreach (current_internal_key[slot]) begin
Expand Down
Loading
Loading