diff --git a/sw/device/silicon_creator/manuf/base/ft_personalize.c b/sw/device/silicon_creator/manuf/base/ft_personalize.c index 56163ba097c232..86aa0f04baad0d 100644 --- a/sw/device/silicon_creator/manuf/base/ft_personalize.c +++ b/sw/device/silicon_creator/manuf/base/ft_personalize.c @@ -430,6 +430,8 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) { &otp_rot_creator_auth_codesign_measurement, &otp_rot_creator_auth_state_measurement, &uds_key_ids, &curr_pubkey, all_certs, &curr_cert_size)); + // DO NOT CHANGE THE "UDS" STRING BELOW with modifying the `dice_cert_names` + // collection in sw/host/provisioning/ft_lib/src/lib.rs. TRY(perso_tlv_prepare_cert_for_shipping("UDS", true, all_certs, curr_cert_size, &perso_blob_to_host)); @@ -446,7 +448,9 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) { &cdi_0_key_ids, &curr_pubkey, all_certs, &curr_cert_size)); cdi_0_offset = perso_blob_to_host.next_free; - TRY(perso_tlv_prepare_cert_for_shipping("CDI_O", false, all_certs, + // DO NOT CHANGE THE "CDI_0" STRING BELOW with modifying the `dice_cert_names` + // collection in sw/host/provisioning/ft_lib/src/lib.rs. + TRY(perso_tlv_prepare_cert_for_shipping("CDI_0", false, all_certs, curr_cert_size, &perso_blob_to_host)); // Generate CDI_1 keys and cert. @@ -463,6 +467,8 @@ static status_t personalize_gen_dice_certificates(ujson_t *uj) { certgen_inputs.owner_security_version, &cdi_1_key_ids, &curr_pubkey, all_certs, &curr_cert_size)); cdi_1_offset = perso_blob_to_host.next_free; + // DO NOT CHANGE THE "CDI_1" STRING BELOW with modifying the `dice_cert_names` + // collection in sw/host/provisioning/ft_lib/src/lib.rs. return perso_tlv_prepare_cert_for_shipping( "CDI_1", false, all_certs, curr_cert_size, &perso_blob_to_host); } diff --git a/sw/host/provisioning/cert_lib/src/lib.rs b/sw/host/provisioning/cert_lib/src/lib.rs index fba023579f1ccb..100af06ce1f6de 100644 --- a/sw/host/provisioning/cert_lib/src/lib.rs +++ b/sw/host/provisioning/cert_lib/src/lib.rs @@ -151,64 +151,139 @@ fn parse_and_endorse_x509_cert_ckms(tbs: Vec, ckms_key_id: &str) -> Result Result { + // Build temp file names for DER and PEM cert files. + let base_name = tmpfilename(base_filename); + let binding_der = base_name.to_owned() + ".der"; + let binding_pem = base_name.to_owned() + ".pem"; + let der_filename = binding_der.as_str(); + let pem_filename = binding_pem.as_str(); + + // Write DER bytes to the tmp file. + let size = get_cert_size(der_cert_bytes)?; + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(der_filename) + .context(format!( + "failed to open temporary DER file: {:?}", + der_filename + ))?; + file.write_all(&der_cert_bytes[0..size])?; + drop(file); + + // Convert the DER cert file to a PEM cert file. + openssl_command(&[ + "x509", + "-out", + pem_filename, + "-in", + der_filename, + "-inform", + "der", + ]) + .context(format!( + "failed to covert DER file ({:?}) to PEM", + der_filename + ))?; + + // Cleanup the intermediate DER file. + fs::remove_file(der_filename).context("failed to remove der file")?; + + Ok(binding_pem) +} + +/// Container for an endorsed certificate. +/// +/// This is used to pass a collection of endorsed certificates, along with metadata, +/// to various functions that check the certificates validate properly with third-party +/// tools. +#[derive(Clone, Debug)] +pub struct EndorsedCert { pub format: CertFormat, + pub name: String, pub bytes: Vec, pub ignore_critical: bool, } -/// Validate a collection of X.509 certificates using 'openssl verify ...' command. +/// Validate a collection of X.509 certificates against a provide CA certificate. /// -/// Each certificate in the collection is validated against the provided CA. +/// Each certificate is validated against the CA using the 'openssl verify ...' command. /// /// Arguments: /// * ca_pem - The file name of the CA certificate saved in PEM format. -/// * certs - A vector of certificate binary blobs. -pub fn validate_certs_chain(ca_pem: &str, certs: &[HostEndorsedCert]) -> Result<()> { - let base_name = tmpfilename("cert_validation"); - let binding_der = base_name.to_owned() + ".der"; - let binding_pem = base_name.to_owned() + ".pem"; - - let der_filename = binding_der.as_str(); - let pem_filename = binding_pem.as_str(); - +/// * certs - A slice of EndorsedCert objects. +pub fn validate_certs(ca_pem: &str, certs: &[EndorsedCert]) -> Result<()> { for cert in certs.iter() { - let size = get_cert_size(&cert.bytes)?; - let mut file = OpenOptions::new() - .write(true) - .truncate(true) - .create(true) - .open(der_filename) - .context("failed to open temporary der file")?; - file.write_all(&cert.bytes[0..size])?; - drop(file); - - openssl_command(&[ - "x509", - "-out", - pem_filename, - "-in", - der_filename, - "-inform", - "der", - ]) - .context("failed to covert DER to PEM")?; + // Write the cert bytes a PEM formated file. + let pem_filename = write_cert_to_temp_pem_file(&cert.bytes, &cert.name)?; // Validate with the fake CA certificate. - let mut validate_args = vec!["verify", "-CAfile", ca_pem]; + let mut args = vec!["verify", "-CAfile", ca_pem]; if cert.ignore_critical { // The `-ignore_critical` critical flag is required to verify // DICE certificates that use the DiceTcbInfo custom extension that // is a TCG standard (critical) extension that is not recognized by // OpenSSL. - validate_args.push("-ignore_critical"); + args.push("-ignore_critical"); } - validate_args.push(pem_filename); - openssl_command(&validate_args).context("failed to verify a certificate chain")?; + args.push(pem_filename.as_str()); + openssl_command(&args).context("failed to verify a certificate chain")?; + + // Cleanup the temp PEM cert file. + fs::remove_file(pem_filename.as_str()).context("failed to remove PEM file")?; } - fs::remove_file(der_filename).context("failed to remove der file")?; - fs::remove_file(pem_filename).context("failed to remove pem file")?; + Ok(()) +} + +/// Validate a chain of X.509 certificates against a provided CA certificate. +/// +/// A chain of X.509 certificates are validated against the CA using the 'openssl verify ...' command. +/// +/// Arguments: +/// * ca_pem - The file name of the CA certificate saved in PEM format. +/// * cert_chain - A slice of EndorsedCert objects representing a chain ordered from root to leaf. +/// * ignore_critical - Whether to pass the `ignore_critical` flag to OpenSSL or not. +pub fn validate_cert_chain( + ca_pem: &str, + cert_chain: &[EndorsedCert], + ignore_critical: bool, +) -> Result<()> { + // Create temp CA PEM file. + let tmp_ca_pem_filename_binding = tmpfilename("tmp_ca_chain.pem"); + let tmp_ca_pem_filename = tmp_ca_pem_filename_binding.as_str(); + fs::copy(ca_pem, tmp_ca_pem_filename)?; + + // Iterate over leaf certs. + let mut tmp_leaf_cert_pem_filename: String = "".to_string(); + for cert in cert_chain.iter() { + // Overwrite the current leaf cert PEM file. + tmp_leaf_cert_pem_filename = write_cert_to_temp_pem_file(&cert.bytes, "leaf")?; + + // Verify the cert chain up to the current leaf cert. + let mut args = vec!["verify", "-CAfile", tmp_ca_pem_filename]; + if ignore_critical { + args.push("-ignore_critical"); + } + args.push(tmp_leaf_cert_pem_filename.as_str()); + openssl_command(&args).context(format!( + "failed to verify a certificate chain at {:?} cert", + cert.name.as_str() + ))?; + + // Append the current leaf cert to the CA PEM file. + let mut tmp_ca_file = OpenOptions::new().append(true).open(tmp_ca_pem_filename)?; + let leaf_cert_pem_contents = fs::read(tmp_leaf_cert_pem_filename.as_str())?; + tmp_ca_file.write_all(&leaf_cert_pem_contents)?; + drop(tmp_ca_file); + } + + // Cleanup the temp PEM cert files. + fs::remove_file(tmp_ca_pem_filename).context("failed to remove temp CA PEM file")?; + fs::remove_file(tmp_leaf_cert_pem_filename.as_str()) + .context("failed to remove temp leaf PEM file")?; Ok(()) } @@ -222,106 +297,123 @@ mod tests { let ca_pem = "./sw/device/silicon_creator/manuf/keys/fake/fake_ca.pem"; // The below byte blobs are proper TPM EK, TPM CEK and TPM CIK certificates // generated during test runs. - let mut cert0: Vec = vec![ - 48, 130, 2, 30, 48, 130, 1, 195, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, 121, - 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, - 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 11, 48, - 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, - 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, 110, 101, - 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, 12, 22, 71, 111, 111, 103, - 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 32, 73, 67, 65, 48, - 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, - 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 48, 91, 49, 11, 48, 9, 6, 3, 85, 4, - 6, 19, 2, 85, 83, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, - 85, 4, 10, 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, - 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 24, 48, 22, 6, 3, 85, 4, 3, - 12, 15, 79, 84, 32, 84, 105, 53, 48, 32, 84, 80, 77, 32, 67, 69, 75, 48, 89, 48, 19, 6, - 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 75, - 36, 92, 59, 242, 87, 205, 181, 243, 64, 67, 94, 55, 61, 212, 203, 207, 248, 209, 47, - 241, 223, 36, 175, 158, 22, 108, 92, 42, 51, 192, 39, 17, 132, 53, 214, 61, 160, 143, - 166, 32, 42, 135, 52, 200, 241, 109, 217, 83, 200, 241, 175, 120, 194, 83, 63, 228, - 215, 73, 172, 68, 56, 35, 128, 163, 89, 48, 87, 48, 15, 6, 3, 85, 29, 15, 1, 1, 255, 4, - 5, 3, 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, 48, 22, 128, 20, 254, 88, - 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, - 32, 6, 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, 74, 231, 83, 121, 12, 253, 134, - 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, - 3, 2, 3, 73, 0, 48, 70, 2, 33, 0, 240, 38, 63, 102, 107, 249, 121, 172, 4, 241, 107, - 165, 35, 37, 171, 90, 48, 66, 147, 139, 113, 70, 180, 79, 150, 47, 104, 12, 150, 152, - 148, 164, 2, 33, 0, 230, 94, 91, 132, 244, 223, 193, 68, 55, 152, 134, 144, 23, 170, - 127, 50, 192, 212, 197, 249, 142, 111, 169, 74, 208, 28, 153, 239, 199, 225, 252, 3, - ]; - let cert1: Vec = vec![ - 48, 130, 2, 30, 48, 130, 1, 196, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, 121, - 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, - 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 11, 48, - 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, - 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, 110, 101, - 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, 12, 22, 71, 111, 111, 103, - 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 32, 73, 67, 65, 48, - 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, - 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 48, 92, 49, 12, 48, 10, 6, 3, 85, - 4, 6, 19, 3, 85, 83, 65, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, - 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, - 12, 11, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 24, 48, 22, 6, 3, 85, - 4, 3, 12, 15, 79, 84, 32, 84, 105, 53, 48, 32, 84, 80, 77, 32, 67, 73, 75, 48, 89, 48, - 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, - 23, 2, 208, 197, 46, 115, 49, 121, 86, 105, 156, 23, 214, 86, 136, 68, 165, 14, 47, 42, - 160, 138, 115, 31, 18, 244, 254, 181, 94, 24, 82, 33, 10, 216, 173, 10, 33, 196, 106, - 167, 143, 159, 150, 126, 119, 105, 95, 94, 173, 171, 168, 79, 117, 84, 122, 225, 159, - 199, 136, 15, 158, 63, 203, 182, 163, 89, 48, 87, 48, 15, 6, 3, 85, 29, 15, 1, 1, 255, - 4, 5, 3, 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, 48, 22, 128, 20, 254, - 88, 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, - 48, 32, 6, 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, 74, 231, 83, 121, 12, 253, - 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, 72, 206, - 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 33, 0, 168, 91, 65, 85, 113, 153, 190, 161, 53, 216, - 6, 110, 144, 236, 235, 241, 120, 29, 68, 169, 78, 127, 249, 176, 134, 165, 37, 201, 53, - 153, 67, 23, 2, 32, 43, 141, 139, 0, 178, 8, 79, 249, 88, 149, 79, 111, 71, 89, 118, - 215, 184, 234, 135, 64, 141, 49, 185, 235, 162, 11, 75, 151, 237, 211, 126, 3, - ]; - let cert2: Vec = vec![ - 48, 130, 2, 120, 48, 130, 2, 31, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, 121, - 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, - 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 11, 48, - 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, - 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, 110, 101, - 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, 12, 22, 71, 111, 111, 103, - 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 32, 73, 67, 65, 48, - 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, - 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, 48, 90, 48, 91, 49, 12, 48, 10, 6, 3, 85, - 4, 6, 19, 3, 85, 83, 65, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, - 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, - 12, 11, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 23, 48, 21, 6, 3, 85, - 4, 3, 12, 14, 79, 84, 32, 84, 105, 53, 48, 32, 84, 80, 77, 32, 69, 75, 48, 89, 48, 19, - 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 35, - 64, 229, 133, 12, 236, 28, 25, 38, 236, 216, 29, 0, 26, 245, 51, 42, 42, 25, 195, 175, - 11, 91, 100, 98, 246, 216, 83, 114, 149, 55, 0, 42, 239, 136, 47, 16, 228, 64, 214, 34, - 187, 164, 143, 120, 232, 148, 219, 93, 47, 206, 9, 22, 74, 236, 168, 12, 71, 249, 167, - 144, 83, 247, 113, 163, 129, 180, 48, 129, 177, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, - 5, 48, 3, 1, 1, 0, 48, 71, 6, 3, 85, 29, 17, 1, 1, 0, 4, 61, 48, 59, 164, 57, 48, 55, - 49, 18, 48, 16, 6, 5, 103, 129, 5, 2, 1, 12, 7, 78, 117, 118, 111, 116, 111, 110, 49, - 15, 48, 13, 6, 5, 103, 129, 5, 2, 2, 12, 4, 84, 105, 53, 48, 49, 16, 48, 14, 6, 5, 103, - 129, 5, 2, 3, 12, 5, 48, 46, 48, 46, 49, 48, 15, 6, 3, 85, 29, 15, 1, 1, 255, 4, 5, 3, - 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, 48, 22, 128, 20, 254, 88, 74, - 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 32, 6, - 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, 74, 231, 83, 121, 12, 253, 134, 1, 163, - 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, - 3, 71, 0, 48, 68, 2, 32, 59, 137, 187, 122, 144, 29, 233, 183, 34, 136, 15, 198, 224, - 76, 4, 142, 107, 206, 21, 193, 69, 82, 158, 66, 52, 5, 7, 143, 0, 128, 166, 12, 2, 32, - 47, 221, 22, 12, 155, 16, 223, 208, 245, 225, 214, 31, 180, 72, 22, 35, 219, 11, 15, - 135, 6, 228, 81, 120, 178, 122, 236, 127, 160, 134, 84, 95, - ]; + let mut cert0 = EndorsedCert { + format: CertFormat::X509, + name: "cert0".to_string(), + ignore_critical: false, + bytes: vec![ + 48, 130, 2, 30, 48, 130, 1, 195, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, + 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, + 42, 134, 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, + 83, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, + 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, + 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, + 12, 22, 71, 111, 111, 103, 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, + 105, 110, 103, 32, 73, 67, 65, 48, 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, + 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, + 48, 90, 48, 91, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 11, 48, 9, 6, 3, + 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, 111, 103, + 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, 110, 101, + 101, 114, 105, 110, 103, 49, 24, 48, 22, 6, 3, 85, 4, 3, 12, 15, 79, 84, 32, 84, + 105, 53, 48, 32, 84, 80, 77, 32, 67, 69, 75, 48, 89, 48, 19, 6, 7, 42, 134, 72, + 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 75, 36, 92, 59, + 242, 87, 205, 181, 243, 64, 67, 94, 55, 61, 212, 203, 207, 248, 209, 47, 241, 223, + 36, 175, 158, 22, 108, 92, 42, 51, 192, 39, 17, 132, 53, 214, 61, 160, 143, 166, + 32, 42, 135, 52, 200, 241, 109, 217, 83, 200, 241, 175, 120, 194, 83, 63, 228, 215, + 73, 172, 68, 56, 35, 128, 163, 89, 48, 87, 48, 15, 6, 3, 85, 29, 15, 1, 1, 255, 4, + 5, 3, 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, 48, 22, 128, 20, 254, + 88, 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, + 18, 48, 32, 6, 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, 74, 231, 83, 121, 12, + 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, 42, 134, + 72, 206, 61, 4, 3, 2, 3, 73, 0, 48, 70, 2, 33, 0, 240, 38, 63, 102, 107, 249, 121, + 172, 4, 241, 107, 165, 35, 37, 171, 90, 48, 66, 147, 139, 113, 70, 180, 79, 150, + 47, 104, 12, 150, 152, 148, 164, 2, 33, 0, 230, 94, 91, 132, 244, 223, 193, 68, 55, + 152, 134, 144, 23, 170, 127, 50, 192, 212, 197, 249, 142, 111, 169, 74, 208, 28, + 153, 239, 199, 225, 252, 3, + ], + }; + let cert1 = EndorsedCert { + format: CertFormat::X509, + name: "cert1".to_string(), + ignore_critical: false, + bytes: vec![ + 48, 130, 2, 30, 48, 130, 1, 196, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, + 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, + 42, 134, 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, + 83, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, + 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, + 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, + 12, 22, 71, 111, 111, 103, 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, + 105, 110, 103, 32, 73, 67, 65, 48, 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, + 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, + 48, 90, 48, 92, 49, 12, 48, 10, 6, 3, 85, 4, 6, 19, 3, 85, 83, 65, 49, 11, 48, 9, + 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, + 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, + 110, 101, 101, 114, 105, 110, 103, 49, 24, 48, 22, 6, 3, 85, 4, 3, 12, 15, 79, 84, + 32, 84, 105, 53, 48, 32, 84, 80, 77, 32, 67, 73, 75, 48, 89, 48, 19, 6, 7, 42, 134, + 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 23, 2, 208, + 197, 46, 115, 49, 121, 86, 105, 156, 23, 214, 86, 136, 68, 165, 14, 47, 42, 160, + 138, 115, 31, 18, 244, 254, 181, 94, 24, 82, 33, 10, 216, 173, 10, 33, 196, 106, + 167, 143, 159, 150, 126, 119, 105, 95, 94, 173, 171, 168, 79, 117, 84, 122, 225, + 159, 199, 136, 15, 158, 63, 203, 182, 163, 89, 48, 87, 48, 15, 6, 3, 85, 29, 15, 1, + 1, 255, 4, 5, 3, 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, 48, 22, 128, + 20, 254, 88, 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, + 34, 209, 18, 48, 32, 6, 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, 74, 231, 83, + 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, + 42, 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 33, 0, 168, 91, 65, 85, 113, + 153, 190, 161, 53, 216, 6, 110, 144, 236, 235, 241, 120, 29, 68, 169, 78, 127, 249, + 176, 134, 165, 37, 201, 53, 153, 67, 23, 2, 32, 43, 141, 139, 0, 178, 8, 79, 249, + 88, 149, 79, 111, 71, 89, 118, 215, 184, 234, 135, 64, 141, 49, 185, 235, 162, 11, + 75, 151, 237, 211, 126, 3, + ], + }; + let cert2 = EndorsedCert { + format: CertFormat::X509, + name: "cert2".to_string(), + ignore_critical: false, + bytes: vec![ + 48, 130, 2, 120, 48, 130, 2, 31, 160, 3, 2, 1, 2, 2, 21, 0, 254, 88, 74, 231, 83, + 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, 48, 10, 6, 8, + 42, 134, 72, 206, 61, 4, 3, 2, 48, 98, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, + 83, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, + 12, 6, 71, 111, 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, + 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 49, 31, 48, 29, 6, 3, 85, 4, 3, + 12, 22, 71, 111, 111, 103, 108, 101, 32, 69, 110, 103, 105, 110, 101, 101, 114, + 105, 110, 103, 32, 73, 67, 65, 48, 34, 24, 15, 50, 48, 50, 51, 48, 49, 48, 49, 48, + 48, 48, 48, 48, 48, 90, 24, 15, 50, 48, 53, 48, 48, 49, 48, 49, 48, 48, 48, 48, 48, + 48, 90, 48, 91, 49, 12, 48, 10, 6, 3, 85, 4, 6, 19, 3, 85, 83, 65, 49, 11, 48, 9, + 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 15, 48, 13, 6, 3, 85, 4, 10, 12, 6, 71, 111, + 111, 103, 108, 101, 49, 20, 48, 18, 6, 3, 85, 4, 11, 12, 11, 69, 110, 103, 105, + 110, 101, 101, 114, 105, 110, 103, 49, 23, 48, 21, 6, 3, 85, 4, 3, 12, 14, 79, 84, + 32, 84, 105, 53, 48, 32, 84, 80, 77, 32, 69, 75, 48, 89, 48, 19, 6, 7, 42, 134, 72, + 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 35, 64, 229, 133, + 12, 236, 28, 25, 38, 236, 216, 29, 0, 26, 245, 51, 42, 42, 25, 195, 175, 11, 91, + 100, 98, 246, 216, 83, 114, 149, 55, 0, 42, 239, 136, 47, 16, 228, 64, 214, 34, + 187, 164, 143, 120, 232, 148, 219, 93, 47, 206, 9, 22, 74, 236, 168, 12, 71, 249, + 167, 144, 83, 247, 113, 163, 129, 180, 48, 129, 177, 48, 15, 6, 3, 85, 29, 19, 1, + 1, 255, 4, 5, 48, 3, 1, 1, 0, 48, 71, 6, 3, 85, 29, 17, 1, 1, 0, 4, 61, 48, 59, + 164, 57, 48, 55, 49, 18, 48, 16, 6, 5, 103, 129, 5, 2, 1, 12, 7, 78, 117, 118, 111, + 116, 111, 110, 49, 15, 48, 13, 6, 5, 103, 129, 5, 2, 2, 12, 4, 84, 105, 53, 48, 49, + 16, 48, 14, 6, 5, 103, 129, 5, 2, 3, 12, 5, 48, 46, 48, 46, 49, 48, 15, 6, 3, 85, + 29, 15, 1, 1, 255, 4, 5, 3, 3, 7, 4, 0, 48, 34, 6, 3, 85, 29, 35, 1, 1, 0, 4, 24, + 48, 22, 128, 20, 254, 88, 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, + 193, 184, 34, 209, 18, 48, 32, 6, 3, 85, 29, 14, 1, 1, 0, 4, 22, 4, 20, 254, 88, + 74, 231, 83, 121, 12, 253, 134, 1, 163, 18, 251, 50, 211, 193, 184, 34, 209, 18, + 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 71, 0, 48, 68, 2, 32, 59, 137, 187, + 122, 144, 29, 233, 183, 34, 136, 15, 198, 224, 76, 4, 142, 107, 206, 21, 193, 69, + 82, 158, 66, 52, 5, 7, 143, 0, 128, 166, 12, 2, 32, 47, 221, 22, 12, 155, 16, 223, + 208, 245, 225, 214, 31, 180, 72, 22, 35, 219, 11, 15, 135, 6, 228, 81, 120, 178, + 122, 236, 127, 160, 134, 84, 95, + ], + }; // Verify that the certificate validation succeeds. - assert!( - validate_certs_chain(ca_pem, &[cert0.clone(), cert1.clone(), cert2.clone()]).is_ok() - ); + assert!(validate_certs(ca_pem, &[cert0.clone(), cert1.clone(), cert2.clone()]).is_ok()); // Corrupt the fist certificate in the chain and verify that the // certificate validation fails. - let bad_value = cert0.pop().unwrap() + 1; - cert0.push(bad_value); - assert!( - validate_certs_chain(ca_pem, &[cert0.clone(), cert1.clone(), cert2.clone()]).is_err() - ); + let bad_value = cert0.bytes.pop().unwrap() + 1; + cert0.bytes.push(bad_value); + assert!(validate_certs(ca_pem, &[cert0.clone(), cert1.clone(), cert2.clone()]).is_err()); } } diff --git a/sw/host/provisioning/ft_lib/src/lib.rs b/sw/host/provisioning/ft_lib/src/lib.rs index fa6a189cd84225..20c181d4175970 100644 --- a/sw/host/provisioning/ft_lib/src/lib.rs +++ b/sw/host/provisioning/ft_lib/src/lib.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use sha2::{Digest, Sha256}; +use std::collections::HashSet; use std::path::PathBuf; use std::time::Duration; @@ -14,8 +15,8 @@ use p256::NistP256; use zerocopy::AsBytes; use cert_lib::{ - get_cert_size, parse_and_endorse_x509_cert, validate_certs_chain, CertEndorsementKey, - HostEndorsedCert, + get_cert_size, parse_and_endorse_x509_cert, validate_cert_chain, validate_certs, + CertEndorsementKey, EndorsedCert, }; use ft_ext_lib::ft_ext; use opentitanlib::app::TransportWrapper; @@ -331,10 +332,14 @@ fn provision_certificates( // 3. hash all certs to check the integrity of what gets written back to the device. let mut cert_hasher = Sha256::new(); let mut start: usize = 0; - let mut host_endorsed_certs: Vec = Vec::new(); + let mut dice_cert_chain: Vec = Vec::new(); + let mut sku_specific_certs: Vec = Vec::new(); let mut num_host_endorsed_certs = 0; let mut endorsed_cert_concat = ArrayVec::::new(); + // DICE certificate names. + let dice_cert_names = HashSet::from(["UDS", "CDI_0", "CDI_1"]); + for _ in 0..perso_blob.num_objs { log::info!("Processing next object"); let header = get_obj_header(&perso_blob.body[start..])?; @@ -361,16 +366,20 @@ fn provision_certificates( let cert = get_cert(&perso_blob.body[start..])?; start += cert.wrapped_size; + // Extract the certificate bytes and endorse the cert if needed. let cert_bytes = if header.obj_type == ObjType::UnendorsedX509Cert { // Endorse the cert and updates its size. let cert_bytes = parse_and_endorse_x509_cert(cert.cert_body.clone(), &key)?; - // Prepare a collection of certs whose endorsements should be checked with OpenSSL. - host_endorsed_certs.push(HostEndorsedCert { - format: CertFormat::X509, - bytes: cert_bytes.clone(), - ignore_critical: if cert.cert_name == "UDS" { true } else { false }, - }); + // Prepare a collection of (SKU-specific) certs whose endorsements should be verified. + if !dice_cert_names.contains(cert.cert_name) { + sku_specific_certs.push(EndorsedCert { + format: CertFormat::X509, + name: cert.cert_name.to_string(), + bytes: cert_bytes.clone(), + ignore_critical: false, + }); + } // Prepare the UJSON data payloads that will be sent back to the device. push_endorsed_cert(&cert_bytes, &cert, &mut endorsed_cert_concat)?; @@ -379,6 +388,17 @@ fn provision_certificates( } else { cert.cert_body }; + + // Collect all DICE certs to validate the chain. + if dice_cert_names.contains(cert.cert_name) { + dice_cert_chain.push(EndorsedCert { + format: CertFormat::X509, + name: cert.cert_name.to_string(), + bytes: cert_bytes.clone(), + ignore_critical: true, + }); + } + // Ensure all certs parse with OpenSSL (even those that where endorsed on device). log::info!("{} Cert: {}", cert.cert_name, hex::encode(&cert_bytes)); let _ = parse_certificate(&cert_bytes)?; @@ -423,9 +443,14 @@ fn provision_certificates( } // Validate the certificate endorsements with OpenSSL. - if !host_endorsed_certs.is_empty() { - validate_certs_chain(ca_certificate.to_str().unwrap(), &host_endorsed_certs)?; + log::info!("Validating DICE certificate chain with OpenSSL ..."); + validate_cert_chain(ca_certificate.to_str().unwrap(), &dice_cert_chain, true)?; + log::info!("Success."); + log::info!("Validating SKU-specific certificates with OpenSSL ..."); + if !sku_specific_certs.is_empty() { + validate_certs(ca_certificate.to_str().unwrap(), &sku_specific_certs)?; } + log::info!("Success."); Ok(()) }