Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the ALLOW_NEW_CONTEXT_TO_EXPORT flag in DeriveContext #400

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
21 changes: 11 additions & 10 deletions verification/client/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,17 @@ type DeriveContextFlags uint32

// Supported flags to DeriveContext
const (
InternalInputInfo DeriveContextFlags = 1 << 31
InternalInputDice DeriveContextFlags = 1 << 30
RetainParentContext DeriveContextFlags = 1 << 29
MakeDefault DeriveContextFlags = 1 << 28
ChangeLocality DeriveContextFlags = 1 << 27
InputAllowCA DeriveContextFlags = 1 << 26
InputAllowX509 DeriveContextFlags = 1 << 25
Recursive DeriveContextFlags = 1 << 24
CdiExport DeriveContextFlags = 1 << 23
CreateCertificate DeriveContextFlags = 1 << 22
InternalInputInfo DeriveContextFlags = 1 << 31
InternalInputDice DeriveContextFlags = 1 << 30
RetainParentContext DeriveContextFlags = 1 << 29
MakeDefault DeriveContextFlags = 1 << 28
ChangeLocality DeriveContextFlags = 1 << 27
InputAllowCA DeriveContextFlags = 1 << 26
InputAllowX509 DeriveContextFlags = 1 << 25
Recursive DeriveContextFlags = 1 << 24
CdiExport DeriveContextFlags = 1 << 23
CreateCertificate DeriveContextFlags = 1 << 22
AllowNewContextToExport DeriveContextFlags = 1 << 21
)

// DeriveContextReq is the input request to DeriveContext
Expand Down
86 changes: 86 additions & 0 deletions verification/testing/deriveContext.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,92 @@ 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)
}
}

// TestDeriveContextAllowedChildCdiExport tests calling DeriveContext with CdiExport flag set and the parent
// set the AllowNewContextToExport flag.
func TestDeriveContextAllowedChildCdiExport(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), client.AllowNewContextToExport, 0, 0)
if err != nil {
t.Fatalf("[ERROR]: Error while making default: %s", err)
}

resp, 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)
}

if err != nil {
t.Fatalf("[ERROR]: Error while exporting CdiExport: %s", err)
}

if resp.ExportedCdi == client.ExportedCdi(bytes.Repeat([]byte{0x0}, 32)) {
t.Fatalf("[FATAL]: Expected ExportedCdi field to be set but was %v", resp.ExportedCdi)
}
if resp.NewContextHandle != client.ContextHandle(bytes.Repeat([]byte{0xFF}, 16)) {
t.Fatalf("[FATAL]: Expected invalid NewContextHandle field but it was set to %v", resp.NewContextHandle)
}
if resp.ParentContextHandle != client.ContextHandle(bytes.Repeat([]byte{0xFF}, 16)) {
t.Fatalf("[FATAL]: Expected invalid ParentContextHandle field but it was set to %v", resp.ParentContextHandle)
}
if resp.CertificateSize == 0 {
t.Fatalf("[FATAL]: Expected CertificateSize to be set but was set to %v", resp.CertificateSize)
}

// Check whether certificate is correctly encoded.
if _, err := x509.ParseCertificate(resp.NewCertificate); err != nil {
t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err)
}
leafCert := checkCertificateStructure(t, resp.NewCertificate)

certChainBytes, err := c.GetCertificateChain()
certChain := checkCertificateChain(t, certChainBytes)
if err != nil {
t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err)
}

// Check all extensions
checkCertificateExtension(t, leafCert.Extensions, nil, nil, true, certChain[len(certChain)-1].SubjectKeyId, true)

// Ensure full certificate chain has valid signatures
// This also checks certificate lifetime, signatures as part of cert chain validation
validateLeafCertChain(t, certChain, leafCert)
}

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