From fb9d4c3a4c479d6bf8365eb9981ef2f3a2d08a8c Mon Sep 17 00:00:00 2001 From: Jordan Hand Date: Wed, 4 Oct 2023 17:21:37 -0700 Subject: [PATCH] Move all tests to use shared test file Make it easier to run DPE tests against different targets by putting all the test cases in a test vector file. This allows test infrastructure for a specific target to add required setup and transport code and then execute the tests in a loop. In particular, this is to support easily running these tests against a Caliptra HwModel target. Additional fixes: * Make hex string conversion use all caps. This matches what Caliptra uses for subject/issuer serialNumber fields. * Support encoding X.509 Directory Strings as either PrintableString or UTF8String. This allows more flexibility when specifying issuer encodings. --- ci.sh | 4 +- crypto/src/signer.rs | 2 +- dpe/src/commands/certify_key.rs | 16 +- dpe/src/x509.rs | 76 +++-- simulator/Cargo.toml | 11 +- .../{certifyKey_test.go => certifyKey.go} | 76 +---- verification/emulator.go | 194 ------------ ...teChain_test.go => getCertificateChain.go} | 42 +-- verification/getProfile.go | 59 ++++ verification/getProfile_test.go | 284 ------------------ verification/go.mod | 2 +- ...zeContext_test.go => initializeContext.go} | 37 +-- verification/profile.go | 20 ++ verification/simulator.go | 39 ++- verification/{tagTCI_test.go => tagTCI.go} | 25 +- verification/transport.go | 54 ++++ verification/verification.go | 83 +++++ verification/verification_test.go | 119 ++------ 18 files changed, 366 insertions(+), 777 deletions(-) rename verification/{certifyKey_test.go => certifyKey.go} (85%) delete mode 100644 verification/emulator.go rename verification/{getCertificateChain_test.go => getCertificateChain.go} (67%) mode change 100755 => 100644 create mode 100644 verification/getProfile.go delete mode 100644 verification/getProfile_test.go rename verification/{initializeContext_test.go => initializeContext.go} (74%) rename verification/{tagTCI_test.go => tagTCI.go} (77%) create mode 100644 verification/transport.go create mode 100644 verification/verification.go diff --git a/ci.sh b/ci.sh index 47274bc2..aaf3ca33 100755 --- a/ci.sh +++ b/ci.sh @@ -54,10 +54,10 @@ function test_rust_targets() { function run_verification_tests() { profile=$1 - cargo build --manifest-path simulator/Cargo.toml #--features=$profile --no-default-features + cargo build --manifest-path simulator/Cargo.toml --features=$profile --no-default-features ( cd verification - go test + go test -v ) } diff --git a/crypto/src/signer.rs b/crypto/src/signer.rs index 465cd289..ca88a939 100644 --- a/crypto/src/signer.rs +++ b/crypto/src/signer.rs @@ -68,7 +68,7 @@ impl CryptoBuf { } let mut curr_idx = 0; - const HEX_CHARS: &[u8; 16] = b"0123456789abcdef"; + const HEX_CHARS: &[u8; 16] = b"0123456789ABCDEF"; for &b in src { let h1 = (b >> 4) as usize; let h2 = (b & 0xF) as usize; diff --git a/dpe/src/commands/certify_key.rs b/dpe/src/commands/certify_key.rs index 121f2451..7ea33c06 100644 --- a/dpe/src/commands/certify_key.rs +++ b/dpe/src/commands/certify_key.rs @@ -5,7 +5,7 @@ use crate::{ dpe_instance::{DpeEnv, DpeInstance, DpeTypes}, response::{CertifyKeyResp, DpeErrorCode, Response, ResponseHdr}, tci::TciNodeData, - x509::{MeasurementData, Name, X509CertWriter}, + x509::{DirectoryString, MeasurementData, Name, X509CertWriter}, DPE_PROFILE, MAX_CERT_SIZE, MAX_HANDLES, }; use bitflags::bitflags; @@ -82,14 +82,16 @@ impl CommandExecution for CertifyKeyCmd { .derive_key_pair(algs, &cdi, &self.label, b"ECC") .map_err(|_| DpeErrorCode::CryptoError)?; - let mut subject_name = Name { - cn: b"DPE Leaf", - serial: [0u8; DPE_PROFILE.get_hash_size() * 2], - }; + let mut subj_serial = [0u8; DPE_PROFILE.get_hash_size() * 2]; env.crypto - .get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subject_name.serial) + .get_pubkey_serial(DPE_PROFILE.alg_len(), &pub_key, &mut subj_serial) .map_err(|_| DpeErrorCode::CryptoError)?; + let subject_name = Name { + cn: DirectoryString::PrintableString(b"DPE Leaf"), + serial: DirectoryString::PrintableString(&subj_serial), + }; + // Get TCI Nodes const INITIALIZER: TciNodeData = TciNodeData::new(); let mut nodes = [INITIALIZER; MAX_HANDLES]; @@ -122,7 +124,7 @@ impl CommandExecution for CertifyKeyCmd { } let mut bytes_written = tbs_writer.encode_ecdsa_tbs( /*serial=*/ - &subject_name.serial[..20], // Serial number must be truncated to 20 bytes + &subject_name.serial.bytes()[..20], // Serial number must be truncated to 20 bytes &issuer_name[..issuer_len], &subject_name, &pub_key, diff --git a/dpe/src/x509.rs b/dpe/src/x509.rs index d0073062..40540b1e 100644 --- a/dpe/src/x509.rs +++ b/dpe/src/x509.rs @@ -13,12 +13,34 @@ use crate::{ use bitflags::bitflags; use crypto::{EcdsaPub, EcdsaSig}; +pub enum DirectoryString<'a> { + PrintableString(&'a [u8]), + Utf8String(&'a [u8]), +} + +impl DirectoryString<'_> { + pub fn len(&self) -> usize { + self.bytes().len() + } + + pub fn is_empty(&self) -> bool { + self.bytes().is_empty() + } + + pub fn bytes(&self) -> &[u8] { + match self { + Self::PrintableString(val) => val, + Self::Utf8String(val) => val, + } + } +} + /// Type for specifying an X.509 RelativeDistinguisedName /// /// `serial` is expected to hold a hex string of the hash of the public key pub struct Name<'a> { - pub cn: &'a [u8], - pub serial: [u8; DPE_PROFILE.get_hash_size() * 2], + pub cn: DirectoryString<'a>, + pub serial: DirectoryString<'a>, } pub struct MeasurementData<'a> { @@ -48,6 +70,7 @@ impl X509CertWriter<'_> { const BIT_STRING_TAG: u8 = 0x3; const OCTET_STRING_TAG: u8 = 0x4; const OID_TAG: u8 = 0x6; + const UTF8_STRING_TAG: u8 = 0xC; const PRINTABLE_STRING_TAG: u8 = 0x13; const GENERALIZE_TIME_TAG: u8 = 0x18; const SEQUENCE_TAG: u8 = 0x30; @@ -187,12 +210,12 @@ impl X509CertWriter<'_> { fn get_rdn_size(name: &Name, tagged: bool) -> Result { let cn_seq_size = Self::get_structure_size( Self::get_bytes_size(&Self::RDN_COMMON_NAME_OID, /*tagged=*/ true)? - + Self::get_bytes_size(name.cn, true)?, + + Self::get_bytes_size(name.cn.bytes(), true)?, /*tagged=*/ true, )?; let serialnumber_seq_size = Self::get_structure_size( Self::get_bytes_size(&Self::RDN_COMMON_NAME_OID, /*tagged=*/ true)? - + Self::get_bytes_size(&name.serial, /*tagged=*/ true)?, + + Self::get_bytes_size(name.serial.bytes(), /*tagged=*/ true)?, /*tagged=*/ true, )?; @@ -507,10 +530,17 @@ impl X509CertWriter<'_> { Ok(bytes_written) } - fn encode_printable_string(&mut self, s: &[u8]) -> Result { - let mut bytes_written = self.encode_tag_field(Self::PRINTABLE_STRING_TAG)?; - bytes_written += self.encode_size_field(s.len())?; - bytes_written += self.encode_bytes(s)?; + /// Encode a DirectoryString for an RDN. Multiple string types are allowed, so + /// this function accepts a `tag`. This is important because some verifiers + /// will do an exact DER comparison when building cert chains. + fn encode_rdn_string(&mut self, s: &DirectoryString) -> Result { + let (val, tag) = match s { + DirectoryString::PrintableString(val) => (val, Self::PRINTABLE_STRING_TAG), + DirectoryString::Utf8String(val) => (val, Self::UTF8_STRING_TAG), + }; + let mut bytes_written = self.encode_tag_field(tag)?; + bytes_written += self.encode_size_field(val.len())?; + bytes_written += self.encode_bytes(val)?; Ok(bytes_written) } @@ -559,7 +589,7 @@ impl X509CertWriter<'_> { bytes_written += self.encode_tag_field(Self::SEQUENCE_TAG)?; bytes_written += self.encode_size_field(cn_size)?; bytes_written += self.encode_oid(&Self::RDN_COMMON_NAME_OID)?; - bytes_written += self.encode_printable_string(name.cn)?; + bytes_written += self.encode_rdn_string(&name.cn)?; // Encode RDN SET bytes_written += self.encode_tag_field(Self::SET_OF_TAG)?; @@ -569,7 +599,7 @@ impl X509CertWriter<'_> { bytes_written += self.encode_tag_field(Self::SEQUENCE_TAG)?; bytes_written += self.encode_size_field(serialnumber_size)?; bytes_written += self.encode_oid(&Self::RDN_SERIALNUMBER_OID)?; - bytes_written += self.encode_printable_string(&name.serial)?; + bytes_written += self.encode_rdn_string(&name.serial)?; Ok(bytes_written) } @@ -1140,7 +1170,7 @@ impl X509CertWriter<'_> { #[cfg(test)] mod tests { use crate::tci::{TciMeasurement, TciNodeData}; - use crate::x509::{MeasurementData, Name, X509CertWriter}; + use crate::x509::{DirectoryString, MeasurementData, Name, X509CertWriter}; use crate::DPE_PROFILE; use crypto::{CryptoBuf, EcdsaPub, EcdsaSig}; use std::str; @@ -1185,8 +1215,8 @@ mod tests { } const TEST_ISSUER: Name = Name { - cn: b"Caliptra Alias", - serial: [0x00; DPE_PROFILE.get_hash_size() * 2], + cn: DirectoryString::PrintableString(b"Caliptra Alias"), + serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]), }; fn encode_test_issuer() -> Vec { @@ -1238,8 +1268,8 @@ mod tests { fn test_rdn() { let mut cert = [0u8; 256]; let test_name = Name { - cn: b"Caliptra Alias", - serial: [0x0u8; DPE_PROFILE.get_hash_size() * 2], + cn: DirectoryString::PrintableString(b"Caliptra Alias"), + serial: DirectoryString::PrintableString(&[0x0u8; DPE_PROFILE.get_hash_size() * 2]), }; let mut w = X509CertWriter::new(&mut cert, true); @@ -1252,8 +1282,8 @@ mod tests { let expected = format!( "CN={}, serialNumber={}", - str::from_utf8(test_name.cn).unwrap(), - str::from_utf8(&test_name.serial).unwrap() + str::from_utf8(test_name.cn.bytes()).unwrap(), + str::from_utf8(&test_name.serial.bytes()).unwrap() ); let actual = name.to_string_with_registry(oid_registry()).unwrap(); assert_eq!(expected, actual); @@ -1353,8 +1383,8 @@ mod tests { let issuer_der = encode_test_issuer(); let test_subject_name = Name { - cn: b"DPE Leaf", - serial: [0x00; DPE_PROFILE.get_hash_size() * 2], + cn: DirectoryString::PrintableString(b"DPE Leaf"), + serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]), }; const ECC_INT_SIZE: usize = DPE_PROFILE.get_ecc_int_size(); @@ -1402,12 +1432,12 @@ mod tests { const TEST_SERIAL: &[u8] = &[0x1F; 20]; const TEST_ISSUER_NAME: Name = Name { - cn: b"Caliptra Alias", - serial: [0x00; DPE_PROFILE.get_hash_size() * 2], + cn: DirectoryString::PrintableString(b"Caliptra Alias"), + serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]), }; const TEST_SUBJECT_NAME: Name = Name { - cn: b"DPE Leaf", - serial: [0x00; DPE_PROFILE.get_hash_size() * 2], + cn: DirectoryString::PrintableString(b"DPE Leaf"), + serial: DirectoryString::PrintableString(&[0x00; DPE_PROFILE.get_hash_size() * 2]), }; const ECC_INT_SIZE: usize = DPE_PROFILE.get_ecc_int_size(); diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 7d0ba7e4..d908a0e9 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -5,6 +5,11 @@ name = "simulator" version = "0.1.0" edition = "2021" +[features] +default = ["dpe_profile_p256_sha256"] +dpe_profile_p256_sha256 = ["dpe/dpe_profile_p256_sha256", "crypto/dpe_profile_p256_sha256", "platform/dpe_profile_p256_sha256"] +dpe_profile_p384_sha384 = ["dpe/dpe_profile_p384_sha384", "crypto/dpe_profile_p384_sha384", "platform/dpe_profile_p384_sha384"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -13,6 +18,6 @@ openssl = "0.10.57" clap = { version = "4.1.8", features = ["derive"] } log = "0.4.17" env_logger = "0.10.0" -dpe = { path = "../dpe" } -crypto = { path = "../crypto", features = ["openssl"] } -platform = { path = "../platform", features = ["openssl"] } +dpe = { path = "../dpe", default-features = false } +crypto = { path = "../crypto", default-features = false, features = ["openssl"] } +platform = { path = "../platform", default-features = false, features = ["openssl"] } diff --git a/verification/certifyKey_test.go b/verification/certifyKey.go similarity index 85% rename from verification/certifyKey_test.go rename to verification/certifyKey.go index 3c4564a8..de984e00 100755 --- a/verification/certifyKey_test.go +++ b/verification/certifyKey.go @@ -11,7 +11,6 @@ import ( "fmt" "log" "reflect" - "strconv" "testing" "time" @@ -117,32 +116,12 @@ const ( type TcgMultiTcbInfo = []DiceTcbInfo -func TestCertifyKey(t *testing.T) { - - supportNeeded := []string{"AutoInit", "X509", "IsCA"} - instance, err := GetTestTarget(supportNeeded) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("[WARNING]: Failed executing TestCertifyKey command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatalf("[FATAL]: %s", err.Error()) - } - } - testCertifyKey(instance, t, false) +func TestCertifyKey(d TestDPEInstance, t *testing.T) { + testCertifyKey(d, t, false) } -func TestCertifyKey_SimulationMode(t *testing.T) { - - supportNeeded := []string{"AutoInit", "Simulation", "X509", "IsCA"} - instance, err := GetTestTarget(supportNeeded) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("[WARNING]: Failed executing TestCertifyKey_SimulationMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatalf("[FATAL]: %s", err.Error()) - } - } - testCertifyKey(instance, t, true) +func TestCertifyKey_SimulationMode(d TestDPEInstance, t *testing.T) { + testCertifyKey(d, t, true) } // Ignores critical extensions that are unknown to x509 package @@ -226,13 +205,9 @@ func checkCertifyKeyTcgUeidExtension(t *testing.T, c *x509.Certificate, label [] t.Errorf("[ERROR]: Error encountered while unmarshalling value of UEID extension, %s", err.Error()) } - t.Logf("[LOG]: Value of UEID extension is %v", ueid.Ueid) - t.Logf("[LOG]: Value of Label passed as input parameter is %v", label) if !reflect.DeepEqual(ueid.Ueid, label) { // Ueid extn value doen not match the label t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") - } else { - t.Logf("[LOG]: tcg-dice-Ueid value matches with the \"Label\" passed in CertifyKeyRequest") } break } @@ -260,8 +235,6 @@ func checkCertifyKeyMultiTcbInfoExtension(t *testing.T, c *x509.Certificate) (Tc if err != nil { // multiTcb info is not provided in leaf t.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) - } else { - t.Logf("[LOG]: MultiTcb extension %v", multiTcbInfo) } break } @@ -292,8 +265,6 @@ func checkCertifyKeyExtendedKeyUsages(t *testing.T, c *x509.Certificate) (*TcgMu if !ext.Critical { t.Errorf("[ERROR]: The Extended Key Usage extension IS NOT CRITICAL, MUST BE CRITICAL") - } else { - t.Logf("[LOG]: The Extended Key Usage extension is marked CRITICAL") } break } @@ -318,7 +289,6 @@ func checkCertifyKeyExtendedKeyUsages(t *testing.T, c *x509.Certificate) (*TcgMu for _, oid := range extKeyUsage { if oid.Equal(expectedKeyUsage) { isExtendedKeyUsageValid = true - t.Logf("[LOG]: Certificate has IsCA: %v and contains specified key usage: %s", c.IsCA, expectedKeyUsageName) break } } @@ -344,9 +314,7 @@ func checkCertifyKeyExtensions(t *testing.T, c *x509.Certificate) { certKeyUsageList := getKeyUsageNames(c.KeyUsage) allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) - if c.KeyUsage == allowedKeyUsages { - t.Logf("[LOG]: Certificate has IsCA: %v and has the expected key usage %v ", c.IsCA, certKeyUsageList) - } else { + if c.KeyUsage != allowedKeyUsages { t.Errorf("[ERROR]: Certificate has IsCA: %v and has got %v but want %v ", c.IsCA, certKeyUsageList, allowedKeyUsageList) } @@ -364,12 +332,8 @@ func checkCertifyKeyBasicConstraints(t *testing.T, c *x509.Certificate, flags ui binary.Write(flagsBuf, binary.LittleEndian, flags) flagIsCA := uint32(CertifyAddIsCA)&flags != 0 - t.Logf("[LOG]: Flags value %d", flags) - t.Logf("[LOG]: Flags bit string %s", strconv.FormatInt(int64(flags), 2)) - if flagIsCA == c.IsCA { - t.Logf("[LOG]: ADD_IS_CA is set to %v and the basic constraint IsCA is set to %v", flagIsCA, c.IsCA) - } else { - t.Errorf("[LOG]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, c.IsCA) + if flagIsCA != c.IsCA { + t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, c.IsCA) } } @@ -401,7 +365,6 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate var x509Cert *x509.Certificate var err error - t.Log("[LOG]: Parse the obtained certificate...") // Check whether certificate is DER encoded. if x509Cert, err = x509.ParseCertificate(certBytes); err != nil { t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) @@ -447,17 +410,17 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate l := registry.ByName(id) // TODO(https://github.com/chipsalliance/caliptra-dpe/issues/74): // Fail the test with Errorf here once we expect it to pass. - t.Logf("[%s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) + t.Logf("[LINT %s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) failed = true } if failed { // Dump the cert in PEM and hex for use with various tools - t.Logf("[ERROR]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ + t.Logf("[LINT]: Offending certificate: %s\n", cert.Subject.String()) + t.Logf("[LINT]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: certBytes, }))) - t.Logf("[ERROR]: Offending certificate (DER):\n%x", certBytes) } return x509Cert } @@ -544,10 +507,7 @@ func testCertifyKey(d TestDPEInstance, t *testing.T, use_simulation bool) { // Run X.509 linter on full certificate chain and file issues for errors leafCert := checkCertificateStructure(t, leafCertBytes) - t.Logf("[LOG]: Leaf certificate is DER encoded") - certChain := checkCertificateChain(t, certChainBytes) - t.Logf("[LOG]: Certificate chain is DER encoded") // Validate that all X.509 fields conform with the format defined in the DPE iRoT profile validateCertifyKeyCert(t, leafCert, uint32(params.Flags), params.Label) @@ -563,15 +523,12 @@ func testCertifyKey(d TestDPEInstance, t *testing.T, use_simulation bool) { // Build certificate chain and calls to validateSignature on each chain. func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { t.Helper() - t.Log("[LOG]: Validating leaf certificate chain...") certsToProcess := []*x509.Certificate{leafCert} // Remove unhandled critical extensions reported by x509 but defined in spec - t.Log("[LOG]: Checking for unhandled critical certificate extensions unknown to DPE certificates profile spec...") removeTcgDiceCriticalExtensions(t, certsToProcess) // Remove unhandled extended key usages reported by x509 but defined in spec - t.Log("[LOG]: Checking for extended key usages unknown to DPE certificates profile spec...") removeTcgDiceExtendedKeyUsages(t, certsToProcess) // Build verify options @@ -581,17 +538,13 @@ func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert chains, err := leafCert.Verify(opts) if err != nil { // Certificate chain cannot be built from leaf to root - t.Errorf("[ERROR]: Error in certificate chain %s: ", err.Error()) + t.Errorf("[ERROR]: Error verifying DPE leaf: %s", err.Error()) } // Log certificate chains linked to leaf - t.Logf("[LOG]: Chains of DPE leaf certificate.") if len(chains) != 1 { - t.Errorf("[ERROR]: certificate chain is empty") + t.Errorf("[ERROR]: Unexpected number of cert chains: %d", len(chains)) } - - // This indicates that signature validation found no errors in the DPE leaf cert chain - t.Logf("[LOG]: DPE leaf certificate chain validation is done") } func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions { @@ -599,9 +552,7 @@ func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.Verify intermediates := x509.NewCertPool() // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. - if certChain[0].Subject.String() == certChain[0].Issuer.String() { - roots.AddCert(certChain[0]) - } + roots.AddCert(certChain[0]) for _, cert := range certChain[1:] { if cert.Subject.String() == cert.Issuer.String() { @@ -614,6 +565,7 @@ func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.Verify Roots: roots, Intermediates: intermediates, CurrentTime: time.Now().UTC(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, } return opts diff --git a/verification/emulator.go b/verification/emulator.go deleted file mode 100644 index 5a12f285..00000000 --- a/verification/emulator.go +++ /dev/null @@ -1,194 +0,0 @@ -// Licensed under the Apache-2.0 license - -package verification - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "net" - "os" - "os/exec" - "syscall" - "time" -) - -// Added the dummy path and flags -const ( - emulatorSocketPath = "/tmp/dpe-emu.socket" - - DPE_EMULATOR_AUTO_INIT_LOCALITY uint32 = 0 - DPE_EMULATOR_OTHER_LOCALITY uint32 = 0 - DPE_EMULATOR_PROFILE Profile = 0 - DPE_EMULATOR_MAX_TCI_NODES uint32 = 0 - DPE_EMULATOR_MAJOR_PROFILE_VERSION uint16 = 0 - DPE_EMULATOR_MINOR_PROFILE_VERSION uint16 = 0 - DPE_EMULATOR_VENDOR_ID uint32 = 0 - DPE_EMULATOR_VENDOR_SKU uint32 = 0 -) - -// Added dummy support for emulator .This is to verify against the support_needed list -var emulator_supports = []string{"AutoInit", "X509"} - -//TODO code for emulator to start, stop, getsupport - -type DpeEmulator struct { - exe_path string - cmd *exec.Cmd - supports Support - currentLocality uint32 - Transport -} - -// Emulator can be started and stopped. -func (s *DpeEmulator) HasPowerControl() bool { - return true -} - -// Start the Emulator. -func (s *DpeEmulator) PowerOn() error { - args := []string{} - if s.supports.Simulation { - args = append(args, "--supports-simulation") - } - if s.supports.ExtendTci { - args = append(args, "--supports-extend-tci") - } - if s.supports.AutoInit { - args = append(args, "--supports-auto-init") - } - if s.supports.Tagging { - args = append(args, "--supports-tagging") - } - if s.supports.RotateContext { - args = append(args, "--supports-rotate-context") - } - if s.supports.X509 { - args = append(args, "--supports-x509") - } - if s.supports.Csr { - args = append(args, "--supports-csr") - } - if s.supports.IsCA { - args = append(args, "--supports-is-ca") - } - if s.supports.IsSymmetric { - args = append(args, "--supports-is-symmetric") - } - if s.supports.InternalInfo { - args = append(args, "--supports-internal-info") - } - if s.supports.InternalDice { - args = append(args, "--supports-internal-dice") - } - - s.cmd = exec.Command(s.exe_path, args...) - s.cmd.Stdout = os.Stdout - err := s.cmd.Start() - if err != nil { - return err - } - if !s.waitForPower( /*on=*/ true) { - return errors.New("the simulator never started") - } - return nil -} - -// Kill the emulator in a way that it can cleanup before closing. -func (s *DpeEmulator) PowerOff() error { - if s.cmd != nil { - err := s.cmd.Process.Signal(syscall.SIGTERM) - if err != nil { - return err - } - if !s.waitForPower( /*on=*/ false) { - return errors.New("the emulator never stopped") - } - } - return nil -} - -// Wait for the emulator to come alive. Timeout at 15 seconds. -func (s *DpeEmulator) waitForPower(on bool) bool { - timeout_seconds := 15 - checks_per_sec := 50 - - for i := 0; i < checks_per_sec*timeout_seconds; i++ { - // Check if the socket file has been created. - if fileExists(simulatorSocketPath) == on { - return true - } - time.Sleep(time.Duration(1000/checks_per_sec) * time.Millisecond) - } - return false -} - -func (s *DpeEmulator) SendCmd(buf []byte) ([]byte, error) { - // Connect to DPE instance. - conn, err := net.Dial("unix", simulatorSocketPath) - if err != nil { - return nil, err - } - - // Prepend the command with the locality. - prepended := bytes.NewBuffer(make([]byte, 0, 4+len(buf))) - if err := binary.Write(prepended, binary.LittleEndian, s.currentLocality); err != nil { - return nil, err - } - if _, err := prepended.Write(buf); err != nil { - return nil, err - } - - // Send the prepended command. - num_sent, err := conn.Write(prepended.Bytes()) - if err != nil { - return nil, err - } - if num_sent != len(prepended.Bytes()) { - return nil, errors.New("didn't send the whole command") - } - - // Get the response. - return io.ReadAll(conn) -} - -func (s *DpeEmulator) GetSupport() *Support { - return &s.supports -} - -func (s *DpeEmulator) GetProfile() Profile { - return DPE_SIMULATOR_PROFILE -} - -func (s *DpeEmulator) GetSupportedLocalities() []uint32 { - return []uint32{DPE_SIMULATOR_AUTO_INIT_LOCALITY, DPE_SIMULATOR_OTHER_LOCALITY} -} - -func (s *DpeEmulator) SetLocality(locality uint32) { - s.currentLocality = locality -} - -func (s *DpeEmulator) GetLocality() uint32 { - return s.currentLocality -} - -func (s *DpeEmulator) GetMaxTciNodes() uint32 { - return DPE_EMULATOR_MAX_TCI_NODES -} - -func (s *DpeEmulator) GetProfileMajorVersion() uint16 { - return DPE_EMULATOR_MAJOR_PROFILE_VERSION -} - -func (s *DpeEmulator) GetProfileMinorVersion() uint16 { - return DPE_EMULATOR_MINOR_PROFILE_VERSION -} - -func (s *DpeEmulator) GetProfileVendorId() uint32 { - return DPE_EMULATOR_VENDOR_ID -} - -func (s *DpeEmulator) GetProfileVendorSku() uint32 { - return DPE_EMULATOR_VENDOR_SKU -} diff --git a/verification/getCertificateChain_test.go b/verification/getCertificateChain.go old mode 100755 new mode 100644 similarity index 67% rename from verification/getCertificateChain_test.go rename to verification/getCertificateChain.go index ef7c4f27..6b3389e2 --- a/verification/getCertificateChain_test.go +++ b/verification/getCertificateChain.go @@ -6,7 +6,6 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "log" "testing" zx509 "github.com/zmap/zcrypto/x509" @@ -14,29 +13,15 @@ import ( "github.com/zmap/zlint/v3/lint" ) -// This file is used to test the Get Certificate Chain command. - -func TestGetCertificateChain(t *testing.T) { - support_needed := []string{"AutoInit", "X509"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("[WARNING]: Failed executing TestGetCertificateChain command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatalf("[ERROR]: %s", err.Error()) - } - } - testGetCertificateChain(instance, t) -} - -func testGetCertificateChain(d TestDPEInstance, t *testing.T) { +func TestGetCertificateChain(d TestDPEInstance, t *testing.T) { if d.HasPowerControl() { err := d.PowerOn() if err != nil { - log.Fatal(err) + t.Fatal(err) } defer d.PowerOff() } + profile, err := GetTransportProfile(d) if err != nil { t.Fatalf("Could not get profile: %v", err) @@ -62,7 +47,6 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { var x509Certs []*x509.Certificate var err error - t.Log("[LOG]: Parse the obtained certificate chain...") // Check whether certificate chain is DER encoded. if x509Certs, err = x509.ParseCertificates(certData); err != nil { t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) @@ -109,17 +93,17 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { l := registry.ByName(id) // TODO(https://github.com/chipsalliance/caliptra-dpe/issues/74): // Fail the test with Errorf here once we expect it to pass. - t.Logf("[%s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) + t.Logf("[LINT %s] %s: %s%s (%s)", level, l.Source, details, l.Description, l.Citation) failed = true } if failed { - // Dump the cert in PEM and hex for use with various tools - t.Logf("[LOG]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ + // Dump the cert in PEM for use with various tools + t.Logf("[LINT]: Offending certificate: %s\n", cert.Subject.String()) + t.Logf("[LINT]: Offending certificate (PEM):\n%s", (string)(pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", - Bytes: certData, + Bytes: cert.Raw, }))) - t.Logf("[LOG]: Offending certificate (DER):\n%x", certData) } } @@ -131,15 +115,12 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { func validateCertChain(t *testing.T, certChain []*x509.Certificate) { t.Helper() - t.Log("[LOG]: Validating intermediate certificates chains...") certsToProcess := certChain // Remove unhandled critical extensions reported by x509 but defined in spec - t.Log("[LOG]: Checking for unhandled critical certificate extensions unknown to DPE certificates profile spec...") removeTcgDiceCriticalExtensions(t, certsToProcess) // Remove unhandled extended key usages reported by x509 but defined in spec - t.Log("[LOG]: Checking for extended key usages unknown to DPE certificates profile spec...") removeTcgDiceExtendedKeyUsages(t, certsToProcess) // Build verify options @@ -153,13 +134,8 @@ func validateCertChain(t *testing.T, certChain []*x509.Certificate) { } // Log certificate chains linked to each cetificate in chain - t.Logf("[LOG]: Chains of intermediate certificate.") if len(chains) != 1 { - t.Errorf("[ERROR]: certificate chain is empty") + t.Errorf("[ERROR]: validateCertChain certificate chain is empty") } } - - // This indicates that signature validation found no errors each cert - // chain of intermediate certificates - t.Logf("[LOG]: Intermediate certificates chain validation is done") } diff --git a/verification/getProfile.go b/verification/getProfile.go new file mode 100644 index 00000000..dbfed012 --- /dev/null +++ b/verification/getProfile.go @@ -0,0 +1,59 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "testing" +) + +// This file is used to test the get profile command. + +func TestGetProfile(d TestDPEInstance, t *testing.T) { + if d.HasPowerControl() { + err := d.PowerOn() + if err != nil { + t.Fatal(err) + } + defer d.PowerOff() + } + + const MIN_TCI_NODES uint32 = 8 + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + client, err := NewClient(d, profile) + if err != nil { + t.Fatalf("Could not initialize client: %v", err) + } + + for _, locality := range d.GetSupportedLocalities() { + d.SetLocality(locality) + rsp, err := client.GetProfile() + if err != nil { + t.Fatalf("Unable to get profile: %v", err) + } + if rsp.MajorVersion != d.GetProfileMajorVersion() { + t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileMajorVersion(), rsp.MajorVersion) + } + if rsp.MinorVersion != d.GetProfileMinorVersion() { + t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileMinorVersion(), rsp.MinorVersion) + } + if rsp.VendorId != d.GetProfileVendorId() { + t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileVendorId(), rsp.VendorId) + } + if rsp.VendorSku != d.GetProfileVendorSku() { + t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileVendorSku(), rsp.VendorSku) + } + if rsp.MaxTciNodes != d.GetMaxTciNodes() { + t.Fatalf("Incorrect max TCI nodes. 0x%08x != 0x%08x", d.GetMaxTciNodes(), rsp.MaxTciNodes) + } + if rsp.MaxTciNodes < MIN_TCI_NODES { + t.Fatalf("DPE instances must be able to support at least %d TCI nodes.", MIN_TCI_NODES) + } + if rsp.Flags != d.GetSupport().ToFlags() { + t.Fatalf("Incorrect support flags. 0x%08x != 0x%08x", d.GetSupport().ToFlags(), rsp.Flags) + } + } +} diff --git a/verification/getProfile_test.go b/verification/getProfile_test.go deleted file mode 100644 index 19d86d81..00000000 --- a/verification/getProfile_test.go +++ /dev/null @@ -1,284 +0,0 @@ -// Licensed under the Apache-2.0 license - -package verification - -import ( - "log" - "testing" -) - -// This file is used to test the get profile command. - -func TestGetProfile(t *testing.T) { - - support_needed := []string{""} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_SimulationMode(t *testing.T) { - - support_needed := []string{"Simulation"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_SimulationMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_ExtendTciMode(t *testing.T) { - - support_needed := []string{"ExtendTci"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_ExtendTciMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_AutoInitMode(t *testing.T) { - - support_needed := []string{"AutoInit"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_AutoInitMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_TaggingMode(t *testing.T) { - - support_needed := []string{"Tagging"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_TaggingMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_RotateContextMode(t *testing.T) { - - support_needed := []string{"RotateContext"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_RotateContextMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_X509Mode(t *testing.T) { - - support_needed := []string{"X509"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_X509Mode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_CsrMode(t *testing.T) { - - support_needed := []string{"Csr"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_CsrMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_IsSymmetricMode(t *testing.T) { - - support_needed := []string{"IsSymmetric"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_IsSymmetricMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_InternalInfoMode(t *testing.T) { - - support_needed := []string{"InternalInfo"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_InternalInfoMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_InternalDiceMode(t *testing.T) { - - support_needed := []string{"InternalDice"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_InternalDiceMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_IsCAMode(t *testing.T) { - - support_needed := []string{"IsCA"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_IsCAMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_SupportMode_01(t *testing.T) { - - support_needed := []string{"Simulation", "AutoInit", "RotateContext", "Csr", "InternalDice", "IsCA"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_SupportMode_01 command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_SupportMode_02(t *testing.T) { - - support_needed := []string{"ExtendTci", "Tagging", "X509", "InternalInfo"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_SupportMode_02 command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func TestGetProfile_AllSupportMode(t *testing.T) { - - support_needed := []string{"Simulation", "ExtendTci", "AutoInit", "Tagging", "RotateContext", "X509", "Csr", "IsSymmetric", "InternalInfo", "InternalDice", "IsCA"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestGetProfile_AllSupportMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testGetProfile(instance, t) -} - -func testGetProfile(d TestDPEInstance, t *testing.T) { - const MIN_TCI_NODES uint32 = 8 - if d.HasPowerControl() { - err := d.PowerOn() - if err != nil { - log.Fatal(err) - } - defer d.PowerOff() - } - profile, err := GetTransportProfile(d) - if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - - client, err := NewClient(d, profile) - if err != nil { - t.Fatalf("Could not initialize client: %v", err) - } - - for _, locality := range d.GetSupportedLocalities() { - d.SetLocality(locality) - rsp, err := client.GetProfile() - if err != nil { - t.Fatalf("Unable to get profile: %v", err) - } - if rsp.MajorVersion != d.GetProfileMajorVersion() { - t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileMajorVersion(), rsp.MajorVersion) - } - if rsp.MinorVersion != d.GetProfileMinorVersion() { - t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileMinorVersion(), rsp.MinorVersion) - } - if rsp.VendorId != d.GetProfileVendorId() { - t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileVendorId(), rsp.VendorId) - } - if rsp.VendorSku != d.GetProfileVendorSku() { - t.Fatalf("Incorrect version. 0x%08x != 0x%08x", d.GetProfileVendorSku(), rsp.VendorSku) - } - if rsp.MaxTciNodes != d.GetMaxTciNodes() { - t.Fatalf("Incorrect max TCI nodes. 0x%08x != 0x%08x", d.GetMaxTciNodes(), rsp.MaxTciNodes) - } - if rsp.MaxTciNodes < MIN_TCI_NODES { - t.Fatalf("DPE instances must be able to support at least %d TCI nodes.", MIN_TCI_NODES) - } - if rsp.Flags != d.GetSupport().ToFlags() { - t.Fatalf("Incorrect support flags. 0x%08x != 0x%08x", d.GetSupport().ToFlags(), rsp.Flags) - } - } -} diff --git a/verification/go.mod b/verification/go.mod index 5c3c9374..f88413a8 100644 --- a/verification/go.mod +++ b/verification/go.mod @@ -1,4 +1,4 @@ -module dpe/verification +module github.com/chipsalliance/caliptra-dpe/verification go 1.20 diff --git a/verification/initializeContext_test.go b/verification/initializeContext.go similarity index 74% rename from verification/initializeContext_test.go rename to verification/initializeContext.go index 4ad3fc0e..40bc6160 100644 --- a/verification/initializeContext_test.go +++ b/verification/initializeContext.go @@ -10,39 +10,10 @@ import ( // This file is used to test the initialize context command. -func TestInitializeContext(t *testing.T) { - - support_needed := []string{""} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestInitializeContext command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - for _, locality := range instance.GetSupportedLocalities() { - instance.SetLocality(locality) - testInitContext(instance, t) - } -} - -func TestInitializeContext_SimulationMode(t *testing.T) { - - support_needed := []string{"Simulation"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestInitializeContext_SimulationMode command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - for _, locality := range instance.GetSupportedLocalities() { - instance.SetLocality(locality) - testInitContext(instance, t) +func TestInitializeContext(d TestDPEInstance, t *testing.T) { + for _, locality := range d.GetSupportedLocalities() { + d.SetLocality(locality) + testInitContext(d, t) } } diff --git a/verification/profile.go b/verification/profile.go index 33a74411..fd46ef12 100644 --- a/verification/profile.go +++ b/verification/profile.go @@ -14,6 +14,26 @@ const ( ProfileP384SHA384 Profile = 2 ) +func (p Profile) GetDigestSize() int { + switch p { + case ProfileP256SHA256: + return 32 + case ProfileP384SHA384: + return 48 + } + return 0 +} + +func (p Profile) GetECCIntSize() int { + switch p { + case ProfileP256SHA256: + return 32 + case ProfileP384SHA384: + return 48 + } + return 0 +} + func (p Profile) String() string { switch p { case ProfileP256SHA256: diff --git a/verification/simulator.go b/verification/simulator.go index 555f5d02..cf8911a9 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -10,6 +10,7 @@ import ( "net" "os" "os/exec" + "reflect" "syscall" "time" ) @@ -17,14 +18,13 @@ import ( const ( simulatorSocketPath = "/tmp/dpe-sim.socket" - DPE_SIMULATOR_AUTO_INIT_LOCALITY uint32 = 0 - DPE_SIMULATOR_OTHER_LOCALITY uint32 = 0x4f544852 - DPE_SIMULATOR_PROFILE Profile = ProfileP256SHA256 - DPE_SIMULATOR_MAX_TCI_NODES uint32 = 24 - DPE_SIMULATOR_MAJOR_PROFILE_VERSION uint16 = CURRENT_PROFILE_MAJOR_VERSION - DPE_SIMULATOR_MINOR_PROFILE_VERSION uint16 = CURRENT_PROFILE_MINOR_VERSION - DPE_SIMULATOR_VENDOR_ID uint32 = 0 - DPE_SIMULATOR_VENDOR_SKU uint32 = 0 + DPE_SIMULATOR_AUTO_INIT_LOCALITY uint32 = 0 + DPE_SIMULATOR_OTHER_LOCALITY uint32 = 0x4f544852 + DPE_SIMULATOR_MAX_TCI_NODES uint32 = 24 + DPE_SIMULATOR_MAJOR_PROFILE_VERSION uint16 = CURRENT_PROFILE_MAJOR_VERSION + DPE_SIMULATOR_MINOR_PROFILE_VERSION uint16 = CURRENT_PROFILE_MINOR_VERSION + DPE_SIMULATOR_VENDOR_ID uint32 = 0 + DPE_SIMULATOR_VENDOR_SKU uint32 = 0 ) type DpeSimulator struct { @@ -159,10 +159,6 @@ func (s *DpeSimulator) GetSupport() *Support { return &s.supports } -func (s *DpeSimulator) GetProfile() Profile { - return DPE_SIMULATOR_PROFILE -} - func (s *DpeSimulator) GetSupportedLocalities() []uint32 { return []uint32{DPE_SIMULATOR_AUTO_INIT_LOCALITY, DPE_SIMULATOR_OTHER_LOCALITY} } @@ -194,3 +190,22 @@ func (s *DpeSimulator) GetProfileVendorId() uint32 { func (s *DpeSimulator) GetProfileVendorSku() uint32 { return DPE_SIMULATOR_VENDOR_SKU } + +// Get the simulator target +func GetSimulatorTarget(support_needed []string, target_exe string) (TestDPEInstance, error) { + + value := reflect.ValueOf(DpeSimulator{}.supports) + fields := reflect.Indirect(value) + fVal := reflect.New(reflect.TypeOf(DpeSimulator{}.supports)) + + for i := 0; i < len(support_needed); i++ { + for j := 0; j < value.NumField(); j++ { + if fields.Type().Field(j).Name == support_needed[i] { + fVal.Elem().Field(j).SetBool(true) + } + } + } + support := fVal.Elem().Interface().(Support) + var instance TestDPEInstance = &DpeSimulator{exe_path: target_exe, supports: support} + return instance, nil +} diff --git a/verification/tagTCI_test.go b/verification/tagTCI.go similarity index 77% rename from verification/tagTCI_test.go rename to verification/tagTCI.go index 31b0e3ff..12dcc09f 100644 --- a/verification/tagTCI_test.go +++ b/verification/tagTCI.go @@ -4,34 +4,17 @@ package verification import ( "errors" - "log" "reflect" "testing" ) // This file is used to test the tagTCI command. -func TestTagTCI(t *testing.T) { - - support_needed := []string{"AutoInit", "Tagging"} - instance, err := GetTestTarget(support_needed) - if err != nil { - if err.Error() == "Requested support is not supported in the emulator" { - t.Skipf("Warning: Failed executing TestTagTCI command due to unsupported request. Hence, skipping the command execution") - } else { - log.Fatal(err) - } - } - - testtagTCI(instance, t) -} - -func testtagTCI(d TestDPEInstance, t *testing.T) { - +func TestTagTCI(d TestDPEInstance, t *testing.T) { if d.HasPowerControl() { err := d.PowerOn() if err != nil { - log.Fatal(err) + t.Fatal(err) } defer d.PowerOff() } @@ -78,12 +61,12 @@ func testtagTCI(d TestDPEInstance, t *testing.T) { t.Fatalf("Could not get tagged TCI: %v", err) } - wantCumulativeTCI := make([]byte, 32) + wantCumulativeTCI := make([]byte, profile.GetDigestSize()) if !reflect.DeepEqual(taggedTCI.CumulativeTCI, wantCumulativeTCI) { t.Errorf("GetTaggedTCI returned cumulative TCI %x, expected %x", taggedTCI.CumulativeTCI, wantCumulativeTCI) } - wantCurrentTCI := make([]byte, 32) + wantCurrentTCI := make([]byte, profile.GetDigestSize()) if !reflect.DeepEqual(taggedTCI.CurrentTCI, wantCurrentTCI) { t.Errorf("GetTaggedTCI returned current TCI %x, expected %x", taggedTCI.CurrentTCI, wantCurrentTCI) } diff --git a/verification/transport.go b/verification/transport.go new file mode 100644 index 00000000..1f85a055 --- /dev/null +++ b/verification/transport.go @@ -0,0 +1,54 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "reflect" +) + +func HasSupportNeeded(d TestDPEInstance, support_needed []string) bool { + support := d.GetSupport() + value := reflect.ValueOf(support) + for i := 0; i < len(support_needed); i++ { + support := reflect.Indirect(value).FieldByName(support_needed[i]) + if !support.Bool() { + return false + } + } + + return true +} + +// An extension to the main DPE transport interface with test hooks. +type TestDPEInstance interface { + Transport + // If power control is unavailable for the given device, return false from + // HasPowerControl and return an error from PowerOn and PowerOff. For devices + // that don't support power control but do have reset capability, return true + // from HasPowerControl leave PowerOn empty and execute the reset in PowerOff. + HasPowerControl() bool + // If supported, turns on the device or starts the emulator/simulator. + PowerOn() error + // If supported, turns of the device, stops the emulator/simulator, or resets. + PowerOff() error + // The Transport implementations are not expected to be able to set the values + // it supports, but this function is used by tests to know how to test the DPE + // instance. + GetSupport() *Support + // Returns a slice of all the localities the instance supports. + GetSupportedLocalities() []uint32 + // Sets the current locality. + SetLocality(locality uint32) + // Gets the current locality. + GetLocality() uint32 + // Returns the Maximum number of the TCIs instance can have. + GetMaxTciNodes() uint32 + // Returns the major version of the profile the instance implements. + GetProfileMajorVersion() uint16 + // Returns the minor version of the profile the instance implements. + GetProfileMinorVersion() uint16 + // Returns the Vendor ID of the profile. + GetProfileVendorId() uint32 + // Returns the vendor's product SKU. + GetProfileVendorSku() uint32 +} diff --git a/verification/verification.go b/verification/verification.go new file mode 100644 index 00000000..a6c03cfa --- /dev/null +++ b/verification/verification.go @@ -0,0 +1,83 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "testing" +) + +type DpeTestFunc func(d TestDPEInstance, t *testing.T) + +type TestCase struct { + Name string + Run DpeTestFunc + SupportNeeded []string +} + +var TestCases = []TestCase{ + // InitializeContext + TestCase{ + "InitializeContext", TestInitializeContext, []string{}, + }, + // CertifyKey + TestCase{ + "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA"}, + }, + TestCase{ + "CertifyKeySimulation", TestCertifyKey_SimulationMode, []string{"AutoInit", "Simulation", "X509", "IsCA"}, + }, + // GetCertificateChain + TestCase{ + "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, + }, + // TagTCI + TestCase{ + "TagTCI", TestTagTCI, []string{"AutoInit", "Tagging"}, + }, + // GetProfile + TestCase{ + "GetProfile", TestGetProfile, []string{}, + }, + TestCase{ + "GetProfile_Simulation", TestGetProfile, []string{"Simulation"}, + }, + TestCase{ + "GetProfile_ExtendTCI", TestGetProfile, []string{"ExtendTci"}, + }, + TestCase{ + "GetProfile_AutoInit", TestGetProfile, []string{"AutoInit"}, + }, + TestCase{ + "GetProfile_Tagging", TestGetProfile, []string{"Tagging"}, + }, + TestCase{ + "GetProfile_RotateContext", TestGetProfile, []string{"RotateContext"}, + }, + TestCase{ + "GetProfile_X509", TestGetProfile, []string{"X509"}, + }, + TestCase{ + "GetProfile_CSR", TestGetProfile, []string{"Csr"}, + }, + TestCase{ + "GetProfile_Symmetric", TestGetProfile, []string{"IsSymmetric"}, + }, + TestCase{ + "GetProfile_InternalInfo", TestGetProfile, []string{"InternalInfo"}, + }, + TestCase{ + "GetProfile_InternalDice", TestGetProfile, []string{"InternalDice"}, + }, + TestCase{ + "GetProfile_IsCA", TestGetProfile, []string{"IsCA"}, + }, + TestCase{ + "GetProfile_Combo01", TestGetProfile, []string{"Simulation", "AutoInit", "RotateContext", "Csr", "InternalDice", "IsCA"}, + }, + TestCase{ + "GetProfile_Combo02", TestGetProfile, []string{"ExtendTci", "Tagging", "X509", "InternalInfo"}, + }, + TestCase{ + "GetProfile_All", TestGetProfile, []string{"Simulation", "ExtendTci", "AutoInit", "Tagging", "RotateContext", "X509", "Csr", "IsSymmetric", "InternalInfo", "InternalDice", "IsCA"}, + }, +} diff --git a/verification/verification_test.go b/verification/verification_test.go index a9f0c9bf..7888df06 100755 --- a/verification/verification_test.go +++ b/verification/verification_test.go @@ -3,19 +3,9 @@ package verification import ( - "errors" "flag" "os" - "reflect" - "strings" "testing" - - "golang.org/x/exp/slices" -) - -const ( - SIMULATOR string = "simulator" - EMULATOR string = "emulator" ) var target_exe *string @@ -23,108 +13,35 @@ var testTargetType string // This will be called before running tests, and it assigns the socket path based on command line flag. func TestMain(m *testing.M) { - flag.StringVar(&testTargetType, "target", "simulator", "allowed target types - emulator, simulator, by default target is simulator") - testTargetType = strings.ToLower(testTargetType) - if testTargetType == SIMULATOR { - target_exe = flag.String("sim", "../simulator/target/debug/simulator", "path to simulator executable") - } else if testTargetType == EMULATOR { - target_exe = flag.String("emu", "../simulator/target/debug/emulator", "path to emulator executable") - } + target_exe = flag.String("sim", "../simulator/target/debug/simulator", "path to simulator executable") exitVal := m.Run() os.Exit(exitVal) } -// An extension to the main DPE transport interface with test hooks. -type TestDPEInstance interface { - Transport - // If power control is unavailable for the given device, return false from - // HasPowerControl and return an error from PowerOn and PowerOff. For devices - // that don't support power control but do have reset capability, return true - // from HasPowerControl leave PowerOn empty and execute the reset in PowerOff. - HasPowerControl() bool - // If supported, turns on the device or starts the emulator/simulator. - PowerOn() error - // If supported, turns of the device, stops the emulator/simulator, or resets. - PowerOff() error - // The Transport implementations are not expected to be able to set the values - // it supports, but this function is used by tests to know how to test the DPE - // instance. - GetSupport() *Support - // Returns the profile the transport supports. - GetProfile() Profile - // Returns a slice of all the localities the instance supports. - GetSupportedLocalities() []uint32 - // Sets the current locality. - SetLocality(locality uint32) - // Gets the current locality. - GetLocality() uint32 - // Returns the Maximum number of the TCIs instance can have. - GetMaxTciNodes() uint32 - // Returns the major version of the profile the instance implements. - GetProfileMajorVersion() uint16 - // Returns the minor version of the profile the instance implements. - GetProfileMinorVersion() uint16 - // Returns the Vendor ID of the profile. - GetProfileVendorId() uint32 - // Returns the vendor's product SKU. - GetProfileVendorSku() uint32 -} - -// Get the test target for simulator/emulator -func GetTestTarget(support_needed []string) (TestDPEInstance, error) { - - if testTargetType == EMULATOR { - for i := 0; i < len(support_needed); i++ { - if !slices.Contains(emulator_supports, support_needed[i]) { - return nil, errors.New("Requested support is not supported in the emulator") +func TestRunAll(t *testing.T) { + for _, test := range TestCases { + t.Run(test.Name, func(t *testing.T) { + d, err := GetTestTarget(test.SupportNeeded) + if err != nil { + t.Errorf("Unable to get test target: %v", err) } - } - instance, err := GetEmulatorTarget(support_needed) - if err != nil { - return nil, err - } - return instance, nil - } else if testTargetType == SIMULATOR { - instance, err := GetSimulatorTarget(support_needed) - if err != nil { - return nil, err - } - instance.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) - return instance, nil - } - return nil, errors.New("Error in creating dpe instances - invalid test target type.") -} -// Get the emulator target -func GetEmulatorTarget(support_needed []string) (TestDPEInstance, error) { + if !HasSupportNeeded(d, test.SupportNeeded) { + t.Skipf("Warning: Target does not have required support, skipping test.") + } - value := reflect.ValueOf(DpeEmulator{}.supports) - for i := 0; i < len(support_needed); i++ { - support := reflect.Indirect(value).FieldByName(support_needed[i]) - if !support.Bool() { - return nil, errors.New("Error in creating dpe instances - supported feature is not enabled in emulator") - } + test.Run(d, t) + }) } - var instance TestDPEInstance = &DpeEmulator{exe_path: *target_exe} - return instance, nil } -// Get the simulator target -func GetSimulatorTarget(support_needed []string) (TestDPEInstance, error) { - - value := reflect.ValueOf(DpeSimulator{}.supports) - fields := reflect.Indirect(value) - fVal := reflect.New(reflect.TypeOf(DpeSimulator{}.supports)) - - for i := 0; i < len(support_needed); i++ { - for j := 0; j < value.NumField(); j++ { - if fields.Type().Field(j).Name == support_needed[i] { - fVal.Elem().Field(j).SetBool(true) - } - } +// Get the test target for simulator/emulator +func GetTestTarget(supportNeeded []string) (TestDPEInstance, error) { + instance, err := GetSimulatorTarget(supportNeeded, *target_exe) + if err != nil { + return nil, err } - support := fVal.Elem().Interface().(Support) - var instance TestDPEInstance = &DpeSimulator{exe_path: *target_exe, supports: support} + instance.SetLocality(DPE_SIMULATOR_AUTO_INIT_LOCALITY) return instance, nil }