Skip to content

Commit

Permalink
Add support for ALLOW_NEW_CONTEXT_TO_EXPORT
Browse files Browse the repository at this point in the history
This flag can be used to either allow or prevent child Contexts to
export a CDI.
  • Loading branch information
clundin25 committed Mar 6, 2025
1 parent e0c847c commit b0ae4d0
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 3 deletions.
134 changes: 133 additions & 1 deletion dpe/src/commands/derive_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ bitflags! {
const RECURSIVE = 1u32 << 24;
const EXPORT_CDI = 1u32 << 23;
const CREATE_CERTIFICATE = 1u32 << 22;
/// ALLOW_NEW_CONTEXT_TO_EXPORT will default to false when omitted.
const ALLOW_NEW_CONTEXT_TO_EXPORT = 1u32 << 21;
}
}

Expand Down Expand Up @@ -103,6 +105,11 @@ impl DeriveContextCmd {
self.flags.contains(DeriveContextFlags::CREATE_CERTIFICATE)
}

pub const fn allows_new_context_to_export(&self) -> bool {
self.flags
.contains(DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT)
}

/// Whether it is okay to make a default context.
///
/// When a default context is in a locality, it MUST be the only context in the locality. This
Expand Down Expand Up @@ -222,6 +229,7 @@ impl CommandExecution for DeriveContextCmd {
|| (self.exports_cdi() && self.retains_parent())
|| (self.exports_cdi()
&& dpe.contexts[parent_idx].context_type == ContextType::Simulation)
|| (self.exports_cdi() && !dpe.contexts[parent_idx].allow_export_cdi())
|| (self.is_recursive() && self.retains_parent())
{
return Err(DpeErrorCode::InvalidArgument);
Expand Down Expand Up @@ -364,6 +372,8 @@ impl CommandExecution for DeriveContextCmd {
allow_x509,
uses_internal_input_info,
uses_internal_input_dice,
allow_export_cdi: self.allows_new_context_to_export()
& tmp_parent_context.allow_export_cdi(),
});

dpe.add_tci_measurement(
Expand Down Expand Up @@ -1039,6 +1049,8 @@ mod tests {
assert!(dpe.contexts[child_idx].allow_x509());
assert!(!dpe.contexts[child_idx].uses_internal_input_info());
assert!(!dpe.contexts[child_idx].uses_internal_input_dice());
// Still using the same context.
assert!(dpe.contexts[child_idx].allow_export_cdi());

// check tci_cumulative correctly computed
let mut hasher = env.crypto.hash_initialize(DPE_PROFILE.alg_len()).unwrap();
Expand Down Expand Up @@ -1215,6 +1227,125 @@ mod tests {
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0])
);

// Children that did not have `DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT` should not
// be able to use `DeriveContextFlags::EXPORT_CDI`.
dpe = DpeInstance::new(
&mut env,
Support::AUTO_INIT | Support::CDI_EXPORT | Support::X509,
)
.unwrap();

let Ok(Response::DeriveContext(res)) = DeriveContextCmd {
handle: ContextHandle::default(),
data: [0xA; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::empty(),
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) else {
panic!("Unexpected result!");
};

let child_idx = dpe.get_active_context_pos(&res.handle, 0).unwrap();
assert!(!dpe.contexts[child_idx].allow_export_cdi());

let res = DeriveContextCmd {
handle: res.handle,
data: [0; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::CREATE_CERTIFICATE,
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]);
assert_eq!(res, Err(DpeErrorCode::InvalidArgument));

// Children that did not have `DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT` should not
// be able to use `DeriveContextFlags::EXPORT_CDI` even if `DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT`
// was included.
dpe = DpeInstance::new(
&mut env,
Support::AUTO_INIT | Support::CDI_EXPORT | Support::X509,
)
.unwrap();

let Ok(Response::DeriveContext(res)) = DeriveContextCmd {
handle: ContextHandle::default(),
data: [0xA; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::empty(),
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) else {
panic!("Unexpected result!");
};
let child_idx = dpe.get_active_context_pos(&res.handle, 0).unwrap();
assert!(!dpe.contexts[child_idx].allow_export_cdi());

let res = DeriveContextCmd {
handle: res.handle,
data: [0; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::EXPORT_CDI
| DeriveContextFlags::CREATE_CERTIFICATE
| DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT,
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]);
assert_eq!(res, Err(DpeErrorCode::InvalidArgument));

// Children whose parents set `DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT` should be able to
// use `DeriveContextFlags::EXPORT_CDI`.

// Create a new env to clear cached exported CDIs
let mut env = DpeEnv::<TestTypes> {
crypto: OpensslCrypto::new(),
platform: DefaultPlatform,
};
dpe = DpeInstance::new(
&mut env,
Support::AUTO_INIT | Support::CDI_EXPORT | Support::X509,
)
.unwrap();

let res = DeriveContextCmd {
handle: ContextHandle::default(),
data: [0xA; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::MAKE_DEFAULT
| DeriveContextFlags::ALLOW_NEW_CONTEXT_TO_EXPORT,
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]);
let child_idx = dpe
.get_active_context_pos(&ContextHandle::default(), 0)
.unwrap();
assert!(dpe.contexts[child_idx].allow_export_cdi());

let res = match res {
Ok(Response::DeriveContext(res)) => res,
_ => panic!("expected to get a valid DeriveContext response."),
};

let res = DeriveContextCmd {
handle: res.handle,
data: [0; DPE_PROFILE.get_tci_size()],
flags: DeriveContextFlags::MAKE_DEFAULT
| DeriveContextFlags::EXPORT_CDI
| DeriveContextFlags::CREATE_CERTIFICATE,
tci_type: 0,
target_locality: TEST_LOCALITIES[0],
}
.execute(&mut dpe, &mut env, TEST_LOCALITIES[0]);
let res = match res {
Ok(Response::DeriveContextExportedCdi(res)) => res,
_ => panic!("expected to get a valid DeriveContextExportedCdi response."),
};
assert_eq!(res.parent_handle, ContextHandle::new_invalid());
assert_eq!(res.handle, ContextHandle::new_invalid());
assert_ne!(res.certificate_size, 0);
assert_ne!(res.new_certificate, [0; MAX_CERT_SIZE]);
assert_ne!(res.exported_cdi, [0; MAX_EXPORTED_CDI_SIZE]);
}
#[test]
fn test_create_ca() {
Expand Down Expand Up @@ -1243,7 +1374,8 @@ mod tests {
.unwrap()
{
Response::DeriveContextExportedCdi(resp) => resp,
_ => panic!("Wrong response type."),
Response::Error(e) => panic!("Got: {:?}", e),
_ => panic!("Got an unexpected response!"),
};
assert_eq!(ContextHandle::new_invalid(), derive_resp.handle);
assert_eq!(ContextHandle::new_invalid(), derive_resp.parent_handle);
Expand Down
1 change: 1 addition & 0 deletions dpe/src/commands/initialize_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl CommandExecution for InitCtxCmd {
allow_x509: true,
uses_internal_input_info: false,
uses_internal_input_dice: false,
allow_export_cdi: true,
});
Ok(Response::InitCtx(NewHandleResp {
handle,
Expand Down
14 changes: 12 additions & 2 deletions dpe/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ pub struct Context {
pub uses_internal_input_dice: U8Bool,
/// Whether this context can emit certificates in X.509 format
pub allow_x509: U8Bool,
pub reserved: [u8; 2],
/// Whether this context can use the `EXPORT_CDI` feature.
pub allow_export_cdi: U8Bool,
pub reserved: [u8; 1],
}

impl Default for Context {
Expand All @@ -53,7 +55,10 @@ impl Context {
uses_internal_input_info: U8Bool::new(false),
uses_internal_input_dice: U8Bool::new(false),
allow_x509: U8Bool::new(false),
reserved: [0; 2],
// The root context needs to
// allow_export_cdi or it is never enabled.
allow_export_cdi: U8Bool::new(true),
reserved: [0; 1],
}
}

Expand All @@ -66,6 +71,9 @@ impl Context {
pub fn allow_x509(&self) -> bool {
self.allow_x509.get()
}
pub fn allow_export_cdi(&self) -> bool {
self.allow_export_cdi.get()
}

/// Sets all values to an initialized state according to ActiveContextArgs
pub fn activate(&mut self, args: &ActiveContextArgs) {
Expand All @@ -81,6 +89,7 @@ impl Context {
self.allow_x509 = args.allow_x509.into();
self.uses_internal_input_info = args.uses_internal_input_info.into();
self.uses_internal_input_dice = args.uses_internal_input_dice.into();
self.allow_export_cdi = args.allow_export_cdi.into();
}

/// Destroy this context so it can no longer be used until it is re-initialized. The default
Expand Down Expand Up @@ -171,6 +180,7 @@ pub struct ActiveContextArgs<'a> {
pub allow_x509: bool,
pub uses_internal_input_info: bool,
pub uses_internal_input_dice: bool,
pub allow_export_cdi: bool,
}

pub(crate) struct ChildToRootIter<'a> {
Expand Down
25 changes: 25 additions & 0 deletions verification/testing/deriveContext.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,31 @@ func TestDeriveContextCdiExport(d client.TestDPEInstance, c client.DPEClient, t
validateLeafCertChain(t, certChain, leafCert)
}

// TestDeriveContextDisallowedChildCdiExport tests calling DeriveContext with CdiExport flag set but the parent
// never set the AllowNewContextToExport flag.
func TestDeriveContextDisallowedChildCdiExport(d client.TestDPEInstance, c client.DPEClient, t *testing.T) {
simulation := false
handle := getInitialContextHandle(d, c, t, simulation)
defer func() {
c.DestroyContext(handle)
}()

profile, err := client.GetTransportProfile(d)
if err != nil {
t.Fatalf("Could not get profile: %v", err)
}
digestLen := profile.GetDigestSize()
res, err := c.DeriveContext(handle, make([]byte, digestLen), 0, 0, 0)
if err != nil {
t.Fatalf("[ERROR]: Error while making default: %s", err)
}

_, err = c.DeriveContext(&res.NewContextHandle, make([]byte, digestLen), client.CdiExport|client.CreateCertificate, 0, 0)
if err == nil {
t.Fatalf("[ERROR]: Expected error when exporting CDI: %s", err)
}
}

// TestChangeLocality validates DerivedChild command with ChangeLocality flag.
func TestChangeLocality(d client.TestDPEInstance, c client.DPEClient, t *testing.T) {
if !d.HasLocalityControl() {
Expand Down
5 changes: 5 additions & 0 deletions verification/testing/simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ func GetSimulatorTargets() []TestTarget {
getTestTarget([]string{"AutoInit", "CdiExport"}),
[]TestCase{TestDeriveContextCdiExportTestCase},
},
{
"TestDeriveContextDisallowedChildCdiExport",
getTestTarget([]string{"AutoInit", "CdiExport"}),
[]TestCase{TestDeriveContextDisallowedChildCdiExportTestCase},
},
{
"DeriveContext_Simulation",
getTestTarget([]string{"AutoInit", "Simulation", "X509", "RetainParentContext"}),
Expand Down
7 changes: 7 additions & 0 deletions verification/testing/verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ var TestDeriveContextCdiExportTestCase = TestCase{
"DeriveContextCdiExport", TestDeriveContextCdiExport, []string{"CdiExport"},
}

// TestDeriveContextDisallowedChildCdiExportTestCase tests DeriveContext
var TestDeriveContextDisallowedChildCdiExportTestCase = TestCase{
"DeriveContextCdiExportDisallowedChild", TestDeriveContextDisallowedChildCdiExport, []string{"CdiExport"},
}

// DeriveContextSimulationTestCase tests DeriveContext with Simulation contexts
var DeriveContextSimulationTestCase = TestCase{
"DeriveContextSimulation", TestDeriveContextSimulation, []string{"AutoInit", "Simulation", "X509", "InternalDice", "InternalInfo", "RetainParentContext"},
Expand Down Expand Up @@ -168,6 +173,8 @@ var AllTestCases = []TestCase{
InitializeContextSimulationTestCase,
InvalidHandleTestCase,
WrongLocalityTestCase,
TestDeriveContextCdiExportTestCase,
TestDeriveContextDisallowedChildCdiExportTestCase,
}

// IrreversibleTestCases contains test cases that are not reversible.
Expand Down

0 comments on commit b0ae4d0

Please sign in to comment.