diff --git a/sw/device/lib/testing/json/provisioning_data.h b/sw/device/lib/testing/json/provisioning_data.h index e798b6b9f4619..d1cab3972965a 100644 --- a/sw/device/lib/testing/json/provisioning_data.h +++ b/sw/device/lib/testing/json/provisioning_data.h @@ -44,7 +44,8 @@ UJSON_SERDE_STRUCT(ManufRmaTokenPersoDataIn, \ #define STRUCT_MANUF_CERT_PERSO_DATA_IN(field, string) \ field(rom_ext_measurement, uint32_t, 8) \ field(owner_manifest_measurement, uint32_t, 8) \ - field(owner_measurement, uint32_t, 8) + field(owner_measurement, uint32_t, 8) \ + field(auth_key_key_id, uint8_t, 20) UJSON_SERDE_STRUCT(ManufCertPersoDataIn, \ manuf_cert_perso_data_in_t, \ STRUCT_MANUF_CERT_PERSO_DATA_IN); @@ -97,7 +98,8 @@ UJSON_SERDE_STRUCT(ManufRmaTokenPersoDataOut, \ */ // clang-format off #define STRUCT_MANUF_CERT_PERSO_DATA_OUT(field, string) \ - field(uds_certificate, ecc_p256_public_key_t) \ + field(uds_certificate, uint8_t, 596) \ + field(uds_certificate_size, size_t) \ field(cdi_0_certificate, ecc_p256_public_key_t) \ field(cdi_1_certificate, ecc_p256_public_key_t) UJSON_SERDE_STRUCT(ManufCertPersoDataOut, \ diff --git a/sw/device/silicon_creator/manuf/provisioning_inputs.bzl b/sw/device/silicon_creator/manuf/provisioning_inputs.bzl index 171eeb94abe73..be738a88b378e 100644 --- a/sw/device/silicon_creator/manuf/provisioning_inputs.bzl +++ b/sw/device/silicon_creator/manuf/provisioning_inputs.bzl @@ -25,6 +25,7 @@ FT_PROVISIONING_INPUTS = _DEVICE_ID_AND_TEST_TOKENS + """ --rom-ext-measurement="0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000" --owner-manifest-measurement="0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000" --owner-measurement="0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000" + --uds-auth-key-id="0x11223344_55667788_99112233_44556677_88991122" """ FT_PERSONALIZE_SIGNING_KEYS = select({ diff --git a/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/BUILD b/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/BUILD index 7ce5b1d9baec3..24a56040c2f6b 100644 --- a/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/BUILD +++ b/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/BUILD @@ -5,10 +5,6 @@ load("@rules_pkg//pkg:tar.bzl", "pkg_tar") load("//rules:const.bzl", "CONST", "hex") load("//rules:manifest.bzl", "manifest") -load( - "//rules:opentitan.bzl", - "RSA_ONLY_KEY_STRUCTS", -) load("//rules:signing.bzl", "offline_presigning_artifacts", "offline_signature_attach") load( "//rules/opentitan:defs.bzl", @@ -16,7 +12,6 @@ load( "hyper310_jtag_params", "opentitan_binary", "opentitan_test", - "rsa_key_for_lc_state", "silicon_jtag_params", ) load( @@ -277,6 +272,7 @@ opentitan_binary( "//sw/device/silicon_creator/lib:attestation_key_diversifiers", "//sw/device/silicon_creator/lib:error", "//sw/device/silicon_creator/lib:otbn_boot_services", + "//sw/device/silicon_creator/lib/cert:uds_template_library", "//sw/device/silicon_creator/lib/drivers:flash_ctrl", "//sw/device/silicon_creator/lib/drivers:hmac", "//sw/device/silicon_creator/lib/drivers:keymgr", @@ -317,10 +313,6 @@ opentitan_test( "//hw/top_earlgrey:fpga_cw310_sival": None, "//hw/top_earlgrey:silicon_creator": None, }, - rsa_key = rsa_key_for_lc_state( - RSA_ONLY_KEY_STRUCTS, - CONST.LCV.PROD, - ), silicon = silicon_jtag_params( binaries = _FT_PROVISIONING_BINARIES, data = ["//sw/device/silicon_creator/manuf/keys/fake:rma_unlock_token_export_key.sk_hsm.der"], diff --git a/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/ft_personalize_3.c b/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/ft_personalize_3.c index 8acc173614b46..0b180508dd9d9 100644 --- a/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/ft_personalize_3.c +++ b/sw/device/silicon_creator/manuf/skus/earlgrey_a0/sival_bringup/ft_personalize_3.c @@ -12,6 +12,7 @@ #include "sw/device/lib/testing/test_framework/ujson_ottf.h" #include "sw/device/silicon_creator/lib/attestation.h" #include "sw/device/silicon_creator/lib/attestation_key_diversifiers.h" +#include "sw/device/silicon_creator/lib/cert/uds.h" // Generated. #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h" #include "sw/device/silicon_creator/lib/drivers/hmac.h" #include "sw/device/silicon_creator/lib/drivers/keymgr.h" @@ -24,18 +25,39 @@ OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true); enum { + /** + * Attestation measurement sizes, comprised of a SHA256 digest. + */ kAttestMeasurementSizeInBits = 256, kAttestMeasurementSizeInBytes = kAttestMeasurementSizeInBits / 8, kAttestMeasurementSizeIn32BitWords = kAttestMeasurementSizeInBytes / sizeof(uint32_t), + + /** + * Certificate Key ID size. + */ + kCertKeyIdSizeInBytes = 20, }; static manuf_cert_perso_data_in_t in_data; -static manuf_cert_perso_data_out_t out_data; static keymgr_binding_value_t attestation_binding_value = {.data = {0}}; static keymgr_binding_value_t sealing_binding_value = {.data = {0}}; static uint32_t rom_ext_measurements[kAttestMeasurementSizeIn32BitWords * 2]; +// Certificate data. +static manuf_cert_perso_data_out_t out_data = { + .uds_certificate = {0}, + .uds_certificate_size = kUdsMaxCertSizeBytes, +}; +static uint8_t curr_attestation_pubkey_x_bytes[kAttestationPublicKeyCoordBytes]; +static uint8_t curr_attestation_pubkey_y_bytes[kAttestationPublicKeyCoordBytes]; +// UDS. +static uint8_t uds_tbs_buffer[kUdsMaxTbsSizeBytes]; +static uds_sig_values_t uds_cert_tbs = { + .tbs = uds_tbs_buffer, + .tbs_size = kUdsMaxTbsSizeBytes, +}; + static const flash_ctrl_perms_t kCertificateFlashInfoPerms = { .read = kMultiBitBool4True, .write = kMultiBitBool4True, @@ -62,6 +84,54 @@ static status_t config_certificate_flash_pages(void) { return OK_STATUS(); } +static status_t gen_uds_keys_and_cert(void) { + // Generate the UDS key. + attestation_public_key_t uds_pubkey = {.x = {0}, .y = {0}}; + TRY(otbn_boot_attestation_keygen(kUdsAttestationKeySeed, + kUdsKeymgrDiversifier, &uds_pubkey)); + memcpy(curr_attestation_pubkey_x_bytes, uds_pubkey.x, + kAttestationPublicKeyCoordBytes); + memcpy(curr_attestation_pubkey_y_bytes, uds_pubkey.y, + kAttestationPublicKeyCoordBytes); + TRY(otbn_boot_attestation_key_save(kUdsAttestationKeySeed, + kUdsKeymgrDiversifier)); + uint8_t creator_pub_key_id[kCertKeyIdSizeInBytes] = {0}; + + // Generate the UDS (unendorsed) UDS certificate. + uds_tbs_values_t uds_cert_tbs_params = { + // TODO(#19455): include OTP measurements in attestation keygen / cert. + // TODO(#19455): include creator pub key ID in cert. + .otp_creator_sw_cfg_hash = NULL, + .otp_creator_sw_cfg_hash_size = 0, + .otp_owner_sw_cfg_hash = NULL, + .otp_owner_sw_cfg_hash_size = 0, + .otp_hw_cfg0_hash = NULL, + .otp_hw_cfg0_hash_size = 0, + .creator_pub_key_id = creator_pub_key_id, + .creator_pub_key_id_size = kCertKeyIdSizeInBytes, + .auth_key_key_id = in_data.auth_key_key_id, + .auth_key_key_id_size = kCertKeyIdSizeInBytes, + .creator_pub_key_ec_x = curr_attestation_pubkey_x_bytes, + .creator_pub_key_ec_x_size = kAttestationPublicKeyCoordBytes, + .creator_pub_key_ec_y = curr_attestation_pubkey_y_bytes, + .creator_pub_key_ec_y_size = kAttestationPublicKeyCoordBytes, + }; + TRY(uds_build_tbs(&uds_cert_tbs_params, uds_cert_tbs.tbs, + &uds_cert_tbs.tbs_size)); + TRY(uds_build_cert(&uds_cert_tbs, out_data.uds_certificate, + &out_data.uds_certificate_size)); + + // Write the (unendorsed) certificate to a flash info page. + TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageUdsCertificate, + kFlashCtrlEraseTypePage)); + TRY(flash_ctrl_info_write(&kFlashCtrlInfoPageUdsCertificate, + kFlashInfoFieldUdsCertificate.byte_offset, + out_data.uds_certificate_size / sizeof(uint32_t), + out_data.uds_certificate)); + + return OK_STATUS(); +} + /** * Crank the keymgr to produce the attestation keys and certificates. */ @@ -70,7 +140,7 @@ static status_t personalize(ujson_t *uj) { LOG_INFO("Waiting for FT provisioning data ..."); TRY(ujson_deserialize_manuf_cert_perso_data_in_t(uj, &in_data)); - // Configure certificat flash info page permissions. + // Configure certificate flash info page permissions. TRY(config_certificate_flash_pages()); // Advance keymgr to Initialized state. @@ -88,29 +158,7 @@ static status_t personalize(ujson_t *uj) { // TODO(#19455): set attestation binding to OTP *Cfg partition measurements. keymgr_advance_state(); TRY(keymgr_state_check(kKeymgrStateCreatorRootKey)); - TRY(otbn_boot_attestation_keygen(kUdsAttestationKeySeed, - kUdsKeymgrDiversifier, &curr_pubkey)); - // TODO(#19455): create certificate and self-sign it. While it will be - // endorsed off-device, i.e., the signature will be replaced, the self-sign - // will be used to gaurantee the integrity of the cert to the host. - // - // Note: the offline endorsement will take place in a secure environment, - // hence we are not taking any measure to authenticate the device to the host. - // - // Until then, we just write the public key to flash and export it over the - // console. - memcpy(out_data.uds_certificate.x, curr_pubkey.x, - kAttestationPublicKeyCoordBytes); - memcpy(out_data.uds_certificate.y, curr_pubkey.y, - kAttestationPublicKeyCoordBytes); - TRY(flash_ctrl_info_erase(&kFlashCtrlInfoPageUdsCertificate, - kFlashCtrlEraseTypePage)); - TRY(flash_ctrl_info_write(&kFlashCtrlInfoPageUdsCertificate, - kFlashInfoFieldUdsCertificate.byte_offset, - sizeof(attestation_public_key_t) / sizeof(uint32_t), - &curr_pubkey)); - TRY(otbn_boot_attestation_key_save(kUdsAttestationKeySeed, - kCdi0KeymgrDiversifier)); + TRY(gen_uds_keys_and_cert()); // Set attestation binding to ROM_EXT / Ownership Manifest measurements. // We set the sealing binding value to all zeros as it is unused in the diff --git a/sw/host/provisioning/ft_lib/src/lib.rs b/sw/host/provisioning/ft_lib/src/lib.rs index 1c5d68c3e6a5c..de5b07810ac0a 100644 --- a/sw/host/provisioning/ft_lib/src/lib.rs +++ b/sw/host/provisioning/ft_lib/src/lib.rs @@ -22,8 +22,8 @@ use opentitanlib::test_utils::load_sram_program::{ use opentitanlib::test_utils::rpc::{UartRecv, UartSend}; use opentitanlib::uart::console::UartConsole; use ujson_lib::provisioning_data::{ - EccP256PublicKey, ManufCertPersoDataIn, ManufFtIndividualizeData, ManufRmaTokenPersoDataIn, - ManufRmaTokenPersoDataOut, + EccP256PublicKey, ManufCertPersoDataIn, ManufCertPersoDataOut, ManufFtIndividualizeData, + ManufRmaTokenPersoDataIn, ManufRmaTokenPersoDataOut, }; pub fn test_unlock( @@ -156,9 +156,9 @@ pub fn run_ft_personalize( transport: &TransportWrapper, init: &InitializeTest, second_bootstrap: PathBuf, - _third_bootstrap: PathBuf, + third_bootstrap: PathBuf, host_ecc_sk: PathBuf, - _attestation_tcb_measurements: &ManufCertPersoDataIn, + perso_data_in: &ManufCertPersoDataIn, timeout: Duration, ) -> Result<()> { let uart = transport.uart("console")?; @@ -216,33 +216,28 @@ pub fn run_ft_personalize( // Wait until device exports the wrapped RMA unlock token. let _ = UartConsole::wait_for(&*uart, r"Exporting FT provisioning data ...", timeout)?; let rma_token_out_data = ManufRmaTokenPersoDataOut::recv(&*uart, timeout, false)?; - // TODO(#19455): write the wrapped RMA unlock token to a file. log::info!("{:x?}", rma_token_out_data); - // TODO(#20580): uncomment when UART RX flakiness is resolved. - //let _ = UartConsole::wait_for(&*uart, r"PASS.*\n", timeout)?; - - // // ------------------------------------------------------------------------- - // // FT Personalize 3 | - // // ------------------------------------------------------------------------- + let _ = UartConsole::wait_for(&*uart, r"PASS.*\n", timeout)?; - // // Bootstrap third personalization binary into flash. - // uart.clear_rx_buffer()?; - // init.bootstrap.load(transport, &_third_bootstrap)?; + // ------------------------------------------------------------------------- + // FT Personalize 3 | + // ------------------------------------------------------------------------- - // // Get UART, set flow control, and wait for test to start running. - // uart.set_flow_control(true)?; - // let _ = UartConsole::wait_for(&*uart, r"Waiting for FT provisioning data ...", timeout)?; + // Bootstrap third personalization binary into flash. + uart.clear_rx_buffer()?; + init.bootstrap.load(transport, &third_bootstrap)?; - // // Send attestation TCB measurements for generating certificates. - // _attestation_tcb_measurements.send(&*uart)?; + // Get UART, set flow control, and wait for test to start running. + uart.set_flow_control(true)?; + let _ = UartConsole::wait_for(&*uart, r"Waiting for FT provisioning data ...", timeout)?; - // // Wait until device exports the attestation certificates. - // let _ = UartConsole::wait_for(&*uart, r"Exporting attestation certificates ...", timeout)?; - // let attestation_cert_out_data = ManufCertPersoDataOut::recv(&*uart, timeout, false)?; - // // TODO(#19455): write the attestation certificates to files. - // log::info!("{:x?}", attestation_cert_out_data); + // Send attestation TCB measurements for generating certificates. + perso_data_in.send(&*uart)?; - // let _ = UartConsole::wait_for(&*uart, r"PASS.*\n", timeout)?; + // Wait until device exports the attestation certificates. + let _ = UartConsole::wait_for(&*uart, r"Exporting attestation certificates ...", timeout)?; + let _ = ManufCertPersoDataOut::recv(&*uart, timeout, false)?; + let _ = UartConsole::wait_for(&*uart, r"PASS.*\n", timeout)?; Ok(()) } diff --git a/sw/host/provisioning/util_lib/src/lib.rs b/sw/host/provisioning/util_lib/src/lib.rs index 607a791e141e4..c151b8da943d9 100644 --- a/sw/host/provisioning/util_lib/src/lib.rs +++ b/sw/host/provisioning/util_lib/src/lib.rs @@ -19,3 +19,16 @@ pub fn hex_string_to_u32_arrayvec(hex_str: &str) -> Result>()) } + +pub fn hex_string_to_u8_arrayvec(hex_str: &str) -> Result> { + let hex_str_no_sep = hex_str.replace('_', ""); + let hex_str_prefix = "0x"; + let sanitized_hex_str = if hex_str.starts_with(hex_str_prefix) { + hex_str_no_sep.strip_prefix(hex_str_prefix).unwrap() + } else { + hex_str_no_sep.as_str() + }; + Ok(decode(sanitized_hex_str)? + .into_iter() + .collect::>()) +} diff --git a/sw/host/tests/manuf/provisioning/ft/src/main.rs b/sw/host/tests/manuf/provisioning/ft/src/main.rs index a658f13b29e23..9aa901e73fd86 100644 --- a/sw/host/tests/manuf/provisioning/ft/src/main.rs +++ b/sw/host/tests/manuf/provisioning/ft/src/main.rs @@ -15,7 +15,7 @@ use opentitanlib::test_utils::init::InitializeTest; use opentitanlib::test_utils::lc::read_lc_state; use opentitanlib::test_utils::load_sram_program::SramProgramParams; use ujson_lib::provisioning_data::{ManufCertPersoDataIn, ManufFtIndividualizeData}; -use util_lib::hex_string_to_u32_arrayvec; +use util_lib::{hex_string_to_u32_arrayvec, hex_string_to_u8_arrayvec}; /// Provisioning data command-line parameters. #[derive(Debug, Args, Clone)] @@ -42,6 +42,10 @@ pub struct ManufFtProvisioningDataInput { #[arg(long)] host_ecc_sk: PathBuf, + /// UDS authority (endorsement) key ID hexstring. + #[arg(long)] + pub uds_auth_key_id: String, + /// Measurement of the ROM_EXT image to be loaded onto the device. #[arg(long)] pub rom_ext_measurement: String, @@ -106,10 +110,13 @@ fn main() -> Result<()> { )?; let owner_measurement = hex_string_to_u32_arrayvec::<8>(opts.provisioning_data.owner_measurement.as_str())?; - let _attestation_tcb_measurements = ManufCertPersoDataIn { + let uds_auth_key_id = + hex_string_to_u8_arrayvec::<20>(opts.provisioning_data.uds_auth_key_id.as_str())?; + let _perso_data_in = ManufCertPersoDataIn { rom_ext_measurement: rom_ext_measurement.clone(), owner_manifest_measurement: owner_manifest_measurement.clone(), owner_measurement: owner_measurement.clone(), + auth_key_key_id: uds_auth_key_id.clone(), }; // Only run test unlock operation if we are in a locked LC state. @@ -184,7 +191,7 @@ fn main() -> Result<()> { opts.second_bootstrap, opts.third_bootstrap, opts.provisioning_data.host_ecc_sk, - &_attestation_tcb_measurements, + &_perso_data_in, opts.timeout, )?;