blob: 6586f2defe7677dab2daef40d62a219fd78bb57e [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This sequence interacts with the C test (sw/device/tests/sim_dv/keymgr_key_derivation.c) and
// performs the checks on digest data
// - In the SW test, write fixed value to OTP for root_key and write creator and owner
// seeds in flash. And then roboot the chip.
// - In the SV sequence, backdoor read Device ID and ROM digest through CSRs.
// - For HardwareRevisionSecret, use the constant values in design.
// - Configure the keymgr and advance to `CreatorRootKey` and `OwnerIntermediateKey`.
// - Check keymgr internal keys after advance operations.
// - Generate identity / SW output for the Sealing CDI.
// - KMAC should finish hashing successfully (not visible to SW) and return digest to
// keymgr.
// - Verify that the keymgr has received valid output from the KMAC.
// - Advance to `Disabled` and verify keymgr enters the state successfully.
// - Generate identity / SW output and ensure these are neither all 1s/0s nor any valid
// key value, which proves secrets are wiped by entropy value from EDN.
//
// - For each operation, wait for the interrupt `op_done` to be triggered and check CSR
// `op_status` is `DONE_SUCCESS`.
class chip_sw_keymgr_key_derivation_vseq extends chip_sw_base_vseq;
`uvm_object_utils(chip_sw_keymgr_key_derivation_vseq)
`uvm_object_new
typedef bit [keymgr_pkg::Shares-1:0][keymgr_pkg::KeyWidth-1:0] key_shares_t;
typedef bit [keymgr_pkg::Shares-1:0][kmac_pkg::AppDigestW-1:0] kmac_digests_t;
typedef struct packed {
bit [keymgr_reg_pkg::NumSwBindingReg-1:0][TL_DW-1:0] SoftwareBinding;
bit [keymgr_pkg::KeyWidth-1:0] HardwareRevisionSecret;
bit [keymgr_pkg::DevIdWidth-1:0] DeviceIdentifier;
bit [keymgr_pkg::HealthStateWidth-1:0] HealthMeasurement;
bit [keymgr_pkg::KeyWidth-1:0] RomDigest;
bit [keymgr_pkg::KeyWidth-1:0] DiversificationKey;
} adv_creator_data_t;
typedef struct packed {
// some portions are unused, which are 0s
bit [keymgr_pkg::AdvDataWidth-keymgr_pkg::KeyWidth-keymgr_pkg::SwBindingWidth-1:0] unused;
bit [keymgr_reg_pkg::NumSwBindingReg-1:0][TL_DW-1:0] SoftwareBinding;
bit [keymgr_pkg::KeyWidth-1:0] OwnerRootSecret;
} adv_owner_int_data_t;
typedef struct packed {
bit [TL_DW-1:0] KeyVersion;
bit [keymgr_reg_pkg::NumSaltReg-1:0][TL_DW-1:0] Salt;
keymgr_pkg::seed_t KeyID;
keymgr_pkg::seed_t SoftwareExportConstant;
} gen_out_data_t;
localparam int KmacDigestBytes = kmac_pkg::AppDigestW / 8;
localparam bit [keymgr_reg_pkg::NumSwBindingReg-1:0][TL_DW-1:0] CreatorSwBinding = {
32'h4ec9c6d6, 32'h19f5cff7, 32'h426dc745, 32'hb8a8379d,
32'he92f76e2, 32'hcb68ff71, 32'haf36e268, 32'hdc96c23d};
localparam bit [keymgr_reg_pkg::NumSwBindingReg-1:0][TL_DW-1:0] OwnerIntSwBinding = {
32'h1940ceeb, 32'hf1394d28, 32'hb012ae5e, 32'h23fb480c,
32'h3195dbfa, 32'hc2f3bbaf, 32'h3f83d390, 32'he4987b39};
localparam bit [flash_ctrl_pkg::SeedWidth-1:0] CreatorFlashSeeds = {
32'ha6521d8f, 32'h13a0e876, 32'h1ca1567b, 32'hb4fb0fdf,
32'h9f89bc56, 32'h4bd127c7, 32'h322288d8, 32'h4e919d54};
localparam bit [flash_ctrl_pkg::SeedWidth-1:0] OwnerFlashSeeds = {
32'h4e919d54, 32'h322288d8, 32'h4bd127c7, 32'h9f89bc56,
32'hb4fb0fdf, 32'h1ca1567b, 32'h13a0e876, 32'ha6521d8f};
localparam bit [keymgr_reg_pkg::NumSaltReg-1:0][TL_DW-1:0] Salt = {
32'hde919d54, 32'h322288d8, 32'h4bd127c7, 32'h9f89bc56,
32'hb4fb0fdf, 32'h1ca1567b, 32'h13a0e876, 32'hb6521d8f};
localparam bit [31:0] SwKeyVersion = 32'h11;
localparam gen_out_data_t GenSWOutData = '{
SwKeyVersion,
Salt,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrNoneSeed,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrSoftOutputSeed};
localparam gen_out_data_t GenKmacOutData = '{
SwKeyVersion,
Salt,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrKmacSeed,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrHardOutputSeed};
localparam gen_out_data_t GenAesOutData = '{
SwKeyVersion,
Salt,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrAesSeed,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrHardOutputSeed};
localparam gen_out_data_t GenOtbnOutData = '{
SwKeyVersion,
Salt,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrOtbnSeed,
top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrHardOutputSeed};
bit lc_at_prod;
virtual task dut_init(string reset_kind = "HARD");
super.dut_init(reset_kind);
void'($value$plusargs("lc_at_prod=%0d", lc_at_prod));
if (lc_at_prod) begin
cfg.mem_bkdr_util_h[Otp].otp_write_lc_partition_state(LcStProd);
end
endtask
virtual task body();
string path_internal_key = "tb.dut.top_earlgrey.u_keymgr.u_ctrl.key_o.key";
key_shares_t new_key;
bit [keymgr_pkg::KeyWidth-1:0] cur_unmasked_key;
bit [keymgr_pkg::KeyWidth-1:0] new_unmasked_key;
bit [keymgr_pkg::AdvDataWidth-1:0] creator_data;
super.body();
// wait and check Keymgr entered CreatorRootKey State
`DV_WAIT(cfg.sw_logger_vif.printed_log == "Keymgr entered CreatorRootKey State")
cur_unmasked_key = get_unmasked_key(get_otp_root_key());
`DV_CHECK_FATAL(uvm_hdl_check_path(path_internal_key))
`DV_CHECK_FATAL(uvm_hdl_read(path_internal_key, new_key))
new_unmasked_key = get_unmasked_key(new_key);
get_creator_data(creator_data);
check_internal_key(cur_unmasked_key, creator_data, new_unmasked_key);
`DV_WAIT(cfg.sw_logger_vif.printed_log == "Keymgr generated identity at CreatorRootKey State")
check_gen_id(new_unmasked_key, top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrCreatorIdentitySeed);
// wait and check Keymgr entered OwnerIntKey State
`DV_WAIT(cfg.sw_logger_vif.printed_log == "Keymgr entered OwnerIntKey State");
cur_unmasked_key = new_unmasked_key;
`DV_CHECK_FATAL(uvm_hdl_read(path_internal_key, new_key))
new_unmasked_key = get_unmasked_key(new_key);
check_internal_key(cur_unmasked_key, get_owner_int_data(), new_unmasked_key);
check_op_in_owner_int_state(new_unmasked_key);
endtask
virtual task check_op_in_owner_int_state(bit [keymgr_pkg::KeyWidth-1:0] unmasked_key);
string path_otbn_key = "tb.dut.top_earlgrey.u_keymgr.otbn_key_o";
bit [keymgr_pkg::KeyWidth-1:0] exp_digest;
bit [keymgr_pkg::KeyWidth-1:0] unused_key;
`DV_WAIT(cfg.sw_logger_vif.printed_log == "Keymgr generated identity at OwnerIntKey State")
check_gen_id(unmasked_key, top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrOwnerIntIdentitySeed);
`DV_WAIT(cfg.sw_logger_vif.printed_log == "Keymgr generated SW output at OwnerIntKey State")
get_sw_shares(exp_digest);
check_gen_out(unmasked_key, GenSWOutData, exp_digest);
// check 3 sideload interfaces
check_kmac_sideload(unmasked_key, unused_key);
check_aes_sideload(unmasked_key, unused_key);
// otbn sideload key is 384 bit, so it's treated a bit differently
begin
keymgr_pkg::otbn_key_req_t otbn_key;
bit [7:0] data_arr[];
bit [kmac_pkg::AppDigestW-1:0] unmask_act_key, unmask_exp_key;
`DV_WAIT(cfg.sw_logger_vif.printed_log ==
"Keymgr generated HW output for Otbn at OwnerIntKey State")
`DV_CHECK_FATAL(uvm_hdl_check_path(path_otbn_key))
`DV_CHECK_FATAL(uvm_hdl_read(path_otbn_key, otbn_key))
`DV_CHECK_EQ(otbn_key.valid, 1)
unmask_act_key = otbn_key.key[0] ^ otbn_key.key[1];
{<< byte {data_arr}} = GenOtbnOutData;
unmask_exp_key = get_kmac_digest(unmasked_key, data_arr);
`DV_CHECK_EQ(unmask_act_key, unmask_exp_key)
end
// The next operation is disable, and key will be wiped and changed every cycle.
$assertoff(0, "tb.dut.top_earlgrey.u_kmac.u_kmac_core.KeyDataStable_M");
endtask
virtual task check_kmac_sideload(bit [keymgr_pkg::KeyWidth-1:0] unmasked_key,
output bit [keymgr_pkg::KeyWidth-1:0] sideload_kmac_key);
keymgr_pkg::hw_key_req_t hw_key;
string path_kmac_key = "tb.dut.top_earlgrey.u_keymgr.kmac_key_o";
`DV_WAIT(cfg.sw_logger_vif.printed_log ==
"Keymgr generated HW output for Kmac at OwnerIntKey State")
`DV_CHECK_FATAL(uvm_hdl_check_path(path_kmac_key))
`DV_CHECK_FATAL(uvm_hdl_read(path_kmac_key, hw_key))
`DV_CHECK_EQ(hw_key.valid, 1)
sideload_kmac_key = get_unmasked_key(hw_key.key);
check_gen_out(unmasked_key, GenKmacOutData, sideload_kmac_key);
endtask
virtual task check_aes_sideload(bit [keymgr_pkg::KeyWidth-1:0] unmasked_key,
output bit [keymgr_pkg::KeyWidth-1:0] sideload_aes_key);
keymgr_pkg::hw_key_req_t hw_key;
string path_aes_key = "tb.dut.top_earlgrey.u_keymgr.aes_key_o";
`DV_WAIT(cfg.sw_logger_vif.printed_log ==
"Keymgr generated HW output for Aes at OwnerIntKey State")
`DV_CHECK_FATAL(uvm_hdl_check_path(path_aes_key))
`DV_CHECK_FATAL(uvm_hdl_read(path_aes_key, hw_key))
`DV_CHECK_EQ(hw_key.valid, 1)
sideload_aes_key = get_unmasked_key(hw_key.key);
check_gen_out(unmasked_key, GenAesOutData, get_unmasked_key(hw_key.key));
endtask
virtual function bit [keymgr_pkg::KeyWidth-1:0] get_unmasked_key(key_shares_t two_share_key);
return two_share_key[0] ^ two_share_key[1];
endfunction
// Here is how the CreatorRootKey data are found
// SoftwareBinding: program fixed value to keymgr CSRs in the C test
// HardwareRevisionSecret: backdoor read CSRs at ral.lc_ctrl.device_id
// HealthMeasurement: HW random constant - RndCnstLcCtrlLcKeymgrDivTestDevRma
// RomDigest: backdoor read CSRs at ral.rom_ctrl_regs.digest
// DiversificationKey: program fixed value to flash in the C test
virtual task get_creator_data(output bit [keymgr_pkg::AdvDataWidth-1:0] creator_data_out);
adv_creator_data_t creator_data;
creator_data.SoftwareBinding = CreatorSwBinding;
creator_data.HardwareRevisionSecret = top_earlgrey_rnd_cnst_pkg::RndCnstKeymgrRevisionSeed;
for (int i = 0; i < keymgr_pkg::DevIdWidth / TL_DW; i++) begin
bit [TL_DW-1:0] rdata;
csr_peek(ral.lc_ctrl.device_id[i], rdata);
creator_data.DeviceIdentifier[TL_DW * i +: TL_DW] = rdata;
end
`uvm_info(`gfn, $sformatf("DeviceIdentifier 0x%0h", creator_data.DeviceIdentifier),
UVM_LOW)
// this test uses either PROD or RMA state
if (lc_at_prod) begin
creator_data.HealthMeasurement =
top_earlgrey_rnd_cnst_pkg::RndCnstLcCtrlLcKeymgrDivProduction;
end else begin
creator_data.HealthMeasurement =
top_earlgrey_rnd_cnst_pkg::RndCnstLcCtrlLcKeymgrDivTestDevRma;
end
for (int i = 0; i < keymgr_pkg::KeyWidth / TL_DW; i++) begin
bit [TL_DW-1:0] rdata;
csr_peek(ral.rom_ctrl_regs.digest[i], rdata);
creator_data.RomDigest[TL_DW * i +: TL_DW] = rdata;
end
`uvm_info(`gfn, $sformatf("RomDigest 0x%0h", creator_data.RomDigest),
UVM_LOW)
creator_data.DiversificationKey = CreatorFlashSeeds;
creator_data_out = keymgr_pkg::AdvDataWidth'(creator_data);
endtask
virtual function bit [keymgr_pkg::AdvDataWidth-1:0] get_owner_int_data();
adv_owner_int_data_t owner_int_data;
owner_int_data.SoftwareBinding = OwnerIntSwBinding;
owner_int_data.OwnerRootSecret = OwnerFlashSeeds;
return keymgr_pkg::AdvDataWidth'(owner_int_data);
endfunction
virtual function key_shares_t get_otp_root_key();
key_shares_t otp_root_key;
// backdoor read CreatorRootKey and descramble the data
for (int i = 0; i < otp_ctrl_reg_pkg::CreatorRootKeyShare0Size / 4; i++) begin
otp_root_key[0][i * 32 +: 32] = cfg.mem_bkdr_util_h[Otp].read32(
otp_ctrl_reg_pkg::CreatorRootKeyShare0Offset + i * 4);
end
for (int i = 0; i < otp_ctrl_reg_pkg::CreatorRootKeyShare0Size / 4 / 2; i++) begin
otp_root_key[0][i * 64 +: 64] = otp_scrambler_pkg::descramble_data(
otp_root_key[0][i * 64 +: 64], otp_ctrl_part_pkg::Secret2Idx);
end
for (int i = 0; i < otp_ctrl_reg_pkg::CreatorRootKeyShare1Size / 4; i++) begin
otp_root_key[1][i * 32 +: 32] = cfg.mem_bkdr_util_h[Otp].read32(
otp_ctrl_reg_pkg::CreatorRootKeyShare1Offset + i * 4);
end
for (int i = 0; i < otp_ctrl_reg_pkg::CreatorRootKeyShare1Size / 4 / 2; i++) begin
otp_root_key[1][i * 64 +: 64] = otp_scrambler_pkg::descramble_data(
otp_root_key[1][i * 64 +: 64], otp_ctrl_part_pkg::Secret2Idx);
end
`uvm_info(`gfn, $sformatf("otp_root_key 0x%0h, 0x%0h", otp_root_key[0], otp_root_key[1]),
UVM_LOW)
return otp_root_key;
endfunction
// a generic kmac digest check function, allow to enter with any length of kmac data
virtual function void check_kmac_digest(
bit [keymgr_pkg::KeyWidth-1:0] kmac_key,
bit [7:0] data_arr[],
bit [keymgr_pkg::KeyWidth-1:0] act_digest);
bit [kmac_pkg::AppDigestW-1:0] digest;
bit [keymgr_pkg::KeyWidth-1:0] exp_digest;
digest = get_kmac_digest(kmac_key, data_arr);
// truncate to 256 bits
exp_digest = keymgr_pkg::KeyWidth'(digest);
`DV_CHECK_EQ(act_digest, exp_digest)
endfunction
// a generic kmac digest check function, allow to enter with any length of kmac data
virtual function bit[kmac_pkg::AppDigestW-1:0] get_kmac_digest(
bit [keymgr_pkg::KeyWidth-1:0] kmac_key,
bit [7:0] data_arr[]);
bit [7:0] key_arr[];
string custom_str = ""; // Just use empty string for top-level tests
bit [7:0] digest_arr[KmacDigestBytes];
bit [kmac_pkg::AppDigestW-1:0] digest;
{<< byte {key_arr}} = kmac_key;
digestpp_dpi_pkg::c_dpi_kmac256(data_arr, data_arr.size(),
key_arr, key_arr.size(),
custom_str,
KmacDigestBytes, digest_arr);
digest = {<< byte {digest_arr}};
return digest;
endfunction
virtual function void check_internal_key(
bit [keymgr_pkg::KeyWidth-1:0] kmac_key,
bit [keymgr_pkg::AdvDataWidth-1:0] kmac_data,
bit [keymgr_pkg::KeyWidth-1:0] act_digest);
bit [7:0] data_arr[];
{<< byte {data_arr}} = kmac_data;
check_kmac_digest(kmac_key, data_arr, act_digest);
endfunction
virtual task check_gen_id(
bit [keymgr_pkg::KeyWidth-1:0] kmac_key,
bit [keymgr_pkg::IdDataWidth-1:0] kmac_data);
bit [7:0] data_arr[];
bit [keymgr_pkg::KeyWidth-1:0] sw_shares;
{<< byte {data_arr}} = kmac_data;
get_sw_shares(sw_shares);
check_kmac_digest(kmac_key, data_arr, sw_shares);
endtask
virtual function void check_gen_out(
bit [keymgr_pkg::KeyWidth-1:0] kmac_key,
bit [keymgr_pkg::GenDataWidth-1:0] kmac_data,
bit [keymgr_pkg::KeyWidth-1:0] exp_digest);
bit [7:0] data_arr[];
{<< byte {data_arr}} = kmac_data;
check_kmac_digest(kmac_key, data_arr, exp_digest);
endfunction
virtual task get_sw_shares(output bit [keymgr_pkg::KeyWidth-1:0] sw_shares);
key_shares_t key_shares;
for (int i = 0; i < keymgr_pkg::KeyWidth / TL_DW; i++) begin
bit [TL_DW-1:0] rdata;
csr_peek(ral.keymgr.sw_share0_output[i], rdata);
key_shares[0][TL_DW * i +: TL_DW] = rdata;
end
for (int i = 0; i < keymgr_pkg::KeyWidth / TL_DW; i++) begin
bit [TL_DW-1:0] rdata;
csr_peek(ral.keymgr.sw_share1_output[i], rdata);
key_shares[1][TL_DW * i +: TL_DW] = rdata;
end
`uvm_info(`gfn, $sformatf("Read SW shares 0x%0h, 0x%0h", key_shares[0], key_shares[1]),
UVM_LOW)
sw_shares = get_unmasked_key(key_shares);
endtask
endclass : chip_sw_keymgr_key_derivation_vseq