Skip to content

Commit f99b4ac

Browse files
authored
Fix up AKCert index attributes (#1550) (#1569)
For now, the AKCert index needs to be owner-defined, not platform-defined. This change will fix up a mitigated vTPM appropriately.
1 parent 7f10fca commit f99b4ac

File tree

1 file changed

+122
-12
lines changed

1 file changed

+122
-12
lines changed

vm/devices/tpm/src/tpm_helper.rs

Lines changed: 122 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,9 @@ impl TpmEngineHelper {
549549
// VM has a small-vTPM mitigation marker. Don't touch anything, but
550550
// log whether the AK cert exists, as that previous write might have
551551
// failed.
552-
let mut output = [0u8; MAX_NV_INDEX_SIZE as usize];
552+
let mut output = vec![0u8; MAX_NV_INDEX_SIZE as usize];
553553
let r = self.read_from_nv_index(TPM_NV_INDEX_AIK_CERT, &mut output);
554-
tracing::warn!("VM has 16k vTPM mitigation marker; not resizing AKCert index");
554+
tracing::warn!("VM has 16k vTPM mitigation marker");
555555
match r {
556556
Err(e) => tracing::error!(
557557
err = &e as &dyn std::error::Error,
@@ -564,7 +564,40 @@ impl TpmEngineHelper {
564564
let nv_bits = TpmaNvBits::from(res.nv_public.nv_public.attributes.0.get());
565565
let size = res.nv_public.nv_public.data_size.get();
566566

567-
tracing::info!(?nv_bits, size, "AKCert index exists")
567+
tracing::info!(?nv_bits, size, "AKCert index exists");
568+
569+
if nv_bits.nv_platformcreate() {
570+
tracing::info!("AKCert index is platform owned; restoring owner auth");
571+
let existing_cert = self.take_existing_ak_cert()?;
572+
if let AkCertType::PlatformOwned(cert) = existing_cert {
573+
self.nv_define_space(
574+
TPM20_RH_OWNER,
575+
0,
576+
TPM_NV_INDEX_AIK_CERT,
577+
cert.len() as u16,
578+
)
579+
.map_err(|error| {
580+
TpmHelperError::TpmCommandError {
581+
command_debug_info: CommandDebugInfo {
582+
command_code: CommandCodeEnum::NV_DefineSpace,
583+
auth_handle: Some(TPM20_RH_OWNER),
584+
nv_index: Some(TPM_NV_INDEX_AIK_CERT),
585+
},
586+
error,
587+
}
588+
})?;
589+
590+
self.nv_write(TPM20_RH_OWNER, None, TPM_NV_INDEX_AIK_CERT, &cert)
591+
.map_err(|error| TpmHelperError::TpmCommandError {
592+
command_debug_info: CommandDebugInfo {
593+
command_code: CommandCodeEnum::NV_Write,
594+
auth_handle: Some(TPM20_RH_OWNER),
595+
nv_index: Some(TPM_NV_INDEX_AIK_CERT),
596+
},
597+
error,
598+
})?;
599+
}
600+
}
568601
}
569602
Ok(NvIndexState::Uninitialized) => {
570603
tracing::warn!("AKCert index uninitialized with mitigation marker")
@@ -635,12 +668,22 @@ impl TpmEngineHelper {
635668
"allocate nv index for previous platform AK cert"
636669
);
637670

671+
let (handle, auth, write_auth_handle) = if will_mitigate_cert {
672+
(TPM20_RH_OWNER, None, TPM20_RH_OWNER)
673+
} else {
674+
(
675+
TPM20_RH_PLATFORM,
676+
Some(auth_value),
677+
ReservedHandle(TPM_NV_INDEX_AIK_CERT.into()),
678+
)
679+
};
680+
638681
let result = self
639-
.nv_define_space(TPM20_RH_PLATFORM, auth_value, TPM_NV_INDEX_AIK_CERT, size)
682+
.nv_define_space(handle, auth.unwrap_or(0), TPM_NV_INDEX_AIK_CERT, size)
640683
.map_err(|error| TpmHelperError::TpmCommandError {
641684
command_debug_info: CommandDebugInfo {
642685
command_code: CommandCodeEnum::NV_DefineSpace,
643-
auth_handle: Some(TPM20_RH_PLATFORM),
686+
auth_handle: Some(handle),
644687
nv_index: Some(TPM_NV_INDEX_AIK_CERT),
645688
},
646689
error,
@@ -668,7 +711,17 @@ impl TpmEngineHelper {
668711
// boot-time AK cert request fails.
669712
tracing::info!("Preserve previous AK cert across boot");
670713

671-
self.write_to_nv_index(auth_value, TPM_NV_INDEX_AIK_CERT, &cert)?;
714+
self.nv_write(write_auth_handle, auth, TPM_NV_INDEX_AIK_CERT, &cert)
715+
.map_err(|error| TpmHelperError::TpmCommandError {
716+
command_debug_info: CommandDebugInfo {
717+
command_code: CommandCodeEnum::NV_Write,
718+
auth_handle: Some(ReservedHandle(
719+
TPM_NV_INDEX_AIK_CERT.into(),
720+
)),
721+
nv_index: Some(TPM_NV_INDEX_AIK_CERT),
722+
},
723+
error,
724+
})?;
672725
}
673726
}
674727
}
@@ -1436,12 +1489,20 @@ impl TpmEngineHelper {
14361489
let session_tag = SessionTagEnum::Sessions;
14371490

14381491
// Use password-based authorization and allow owner to read
1439-
let attributes = TpmaNvBits::new()
1440-
.with_nv_authread(true)
1441-
.with_nv_authwrite(true)
1442-
.with_nv_ownerread(true)
1443-
.with_nv_platformcreate(true)
1444-
.with_nv_no_da(true);
1492+
let attributes = if auth_handle == TPM20_RH_PLATFORM {
1493+
TpmaNvBits::new()
1494+
.with_nv_authread(true)
1495+
.with_nv_authwrite(true)
1496+
.with_nv_ownerread(true)
1497+
.with_nv_platformcreate(true)
1498+
.with_nv_no_da(true)
1499+
} else {
1500+
TpmaNvBits::new()
1501+
.with_nv_ownerread(true)
1502+
.with_nv_ownerwrite(true)
1503+
.with_nv_authread(true)
1504+
.with_nv_authwrite(true)
1505+
};
14451506

14461507
let public_info = TpmsNvPublic::new(
14471508
nv_index,
@@ -3552,4 +3613,53 @@ mod tests {
35523613
panic!()
35533614
}
35543615
}
3616+
3617+
#[test]
3618+
fn test_restore_owner_defined() {
3619+
const AK_CERT_INPUT_512: [u8; 512] = [7u8; 512];
3620+
3621+
let mut tpm_engine_helper = create_tpm_engine_helper();
3622+
restart_tpm_engine(&mut tpm_engine_helper, false, true);
3623+
3624+
// Test allocating a platform-defined AKCert index and mitigating it back to owner-defined.
3625+
3626+
let result =
3627+
tpm_engine_helper.allocate_guest_attestation_nv_indices(AUTH_VALUE, false, true, false);
3628+
assert!(result.is_ok());
3629+
3630+
let result = tpm_engine_helper
3631+
.find_nv_index(TPM_NV_INDEX_AIK_CERT)
3632+
.expect("find_nv_index should succeed")
3633+
.expect("AKCert NV index present");
3634+
let nv_bits = TpmaNvBits::from(result.nv_public.nv_public.attributes.0.get());
3635+
assert!(nv_bits.nv_platformcreate());
3636+
3637+
let result = tpm_engine_helper.write_to_nv_index(
3638+
AUTH_VALUE,
3639+
TPM_NV_INDEX_AIK_CERT,
3640+
&AK_CERT_INPUT_512,
3641+
);
3642+
assert!(result.is_ok());
3643+
3644+
let result = tpm_engine_helper.nv_define_space(
3645+
TPM20_RH_PLATFORM,
3646+
AUTH_VALUE,
3647+
TPM_NV_INDEX_MITIGATED,
3648+
1,
3649+
);
3650+
assert!(result.is_ok());
3651+
3652+
// TPM has a platform-defined AKCert index and a mitigation marker. This should restore
3653+
// the owner-defined AKCert index.
3654+
let result =
3655+
tpm_engine_helper.allocate_guest_attestation_nv_indices(AUTH_VALUE, false, true, true);
3656+
assert!(result.is_ok());
3657+
3658+
let result = tpm_engine_helper
3659+
.find_nv_index(TPM_NV_INDEX_AIK_CERT)
3660+
.expect("find_nv_index should succeed")
3661+
.expect("AKCert NV index present");
3662+
let nv_bits = TpmaNvBits::from(result.nv_public.nv_public.attributes.0.get());
3663+
assert!(!nv_bits.nv_platformcreate());
3664+
}
35553665
}

0 commit comments

Comments
 (0)