From 97f49128304aa811a8d6279535a211cab9dc98fe Mon Sep 17 00:00:00 2001 From: Tim Trippel Date: Thu, 8 Feb 2024 13:30:23 -0800 Subject: [PATCH] [personalize] generate unendorsed UDS certificate on the device This update the personalization firmware to generate the UDS certificate on the device, and write it out over the console so it may be endorsed. Signed-off-by: Tim Trippel --- .../lib/testing/json/provisioning_data.h | 6 +- .../manuf/provisioning_inputs.bzl | 1 + .../skus/earlgrey_a0/sival_bringup/BUILD | 10 +- .../sival_bringup/ft_personalize_3.c | 98 ++++++++++++++----- sw/host/provisioning/ft_lib/src/lib.rs | 45 ++++----- sw/host/provisioning/util_lib/src/lib.rs | 13 +++ .../tests/manuf/provisioning/ft/src/main.rs | 13 ++- 7 files changed, 122 insertions(+), 64 deletions(-) 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, )?;