diff --git a/verification/sim/go.mod b/verification/sim/go.mod new file mode 100644 index 00000000..9ed6b530 --- /dev/null +++ b/verification/sim/go.mod @@ -0,0 +1,7 @@ +module github.com/chipsalliance/caliptra-dpe/verification/sim + +go 1.18 + +replace github.com/chipsalliance/caliptra-dpe/verification/client => ../client + +require github.com/chipsalliance/caliptra-dpe/verification/client v0.0.0-20240216212309-5c9f6edaeb55 diff --git a/verification/sim/transport.go b/verification/sim/transport.go new file mode 100644 index 00000000..938efcd7 --- /dev/null +++ b/verification/sim/transport.go @@ -0,0 +1,230 @@ +// Licensed under the Apache-2.0 license + +// Package sim implements DPE transport for the DPE software simulator +package sim + +import ( + "bytes" + "encoding/binary" + "errors" + "io" + "net" + "os" + "os/exec" + "syscall" + "time" + + "github.com/chipsalliance/caliptra-dpe/verification/client" +) + +// Constants for configuring expected values from the DPE simulator +const ( + simulatorSocketPath = "/tmp/dpe-sim.socket" + + DPESimulatorAutoInitLocality uint32 = 0 + DPESimulatorOtherLocality uint32 = 0x4f544852 + DPESimulatorMaxTCINodes uint32 = 24 + DPESimulatorMajorProfileVersion uint16 = client.CurrentProfileMajorVersion + DPESimulatorMinorProfileVersion uint16 = client.CurrentProfileMinorVersion + DPESimulatorVendorID uint32 = 0 + DPESimulatorVendorSKU uint32 = 0 +) + +// DpeSimulator is a handle to a DPE simulator instance +// +// DpeSimulator implements the client.Transport and verification.TestTarget +// interfaces. +type DpeSimulator struct { + exePath string + cmd *exec.Cmd + supports client.Support + currentLocality uint32 + isInitialized bool + client.Transport +} + +func NewSimulator(exe string, support client.Support) DpeSimulator { + return DpeSimulator{exePath: exe, supports: support} +} + +// HasPowerControl returns whether the simulator can be started and stopped. +func (s *DpeSimulator) HasPowerControl() bool { + return true +} + +// PowerOn starts the simulator. +func (s *DpeSimulator) PowerOn() error { + args := []string{} + if s.supports.Simulation { + args = append(args, "--supports-simulation") + } + if s.supports.Recursive { + args = append(args, "--supports-recursive") + } + if s.supports.AutoInit { + args = append(args, "--supports-auto-init") + } + 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") + } + if s.supports.RetainParentContext { + args = append(args, "--supports-retain-parent-context") + } + + s.cmd = exec.Command(s.exePath, 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 +} + +// PowerOff kills the simulator in a way that it can cleanup before closing. +func (s *DpeSimulator) 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 simulator never stopped") + } + } + return nil +} + +// Wait for the simulator to come alive. Timeout at 15 seconds. +func (s *DpeSimulator) waitForPower(on bool) bool { + timeoutSeconds := 15 + checksPerSec := 50 + + for i := 0; i < checksPerSec*timeoutSeconds; i++ { + // Check if the socket file has been created. + if fileExists(simulatorSocketPath) == on { + return true + } + time.Sleep(time.Duration(1000/checksPerSec) * time.Millisecond) + } + return false +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +// SendCmd sends a DPE command to the simulator +func (s *DpeSimulator) 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. + numSent, err := conn.Write(prepended.Bytes()) + if err != nil { + return nil, err + } + if numSent != len(prepended.Bytes()) { + return nil, errors.New("didn't send the whole command") + } + + // Get the response. + return io.ReadAll(conn) +} + +// GetSupport gets supported DPE features from the simulator +func (s *DpeSimulator) GetSupport() *client.Support { + return &s.supports +} + +// GetIsInitialized gets whether DPE is initialized +func (s *DpeSimulator) GetIsInitialized() bool { + return s.supports.AutoInit || s.isInitialized +} + +// SetIsInitialized sets whether DPE is initialized +func (s *DpeSimulator) SetIsInitialized(isInitialized bool) { + s.isInitialized = isInitialized +} + +// GetSupportedLocalities gets the list of localities the simulator supports +func (s *DpeSimulator) GetSupportedLocalities() []uint32 { + return []uint32{DPESimulatorAutoInitLocality, DPESimulatorOtherLocality} +} + +// HasLocalityControl returns whether the simulator can artificially set the +// locality of the caller. The simulator target can always control the locality. +func (s *DpeSimulator) HasLocalityControl() bool { + return true +} + +// SetLocality sets the locality of this caller +func (s *DpeSimulator) SetLocality(locality uint32) { + s.currentLocality = locality +} + +// GetLocality gets the locality of the current caller +func (s *DpeSimulator) GetLocality() uint32 { + return s.currentLocality +} + +// GetMaxTciNodes gets the max number of TCI nodes the DPE supports +func (s *DpeSimulator) GetMaxTciNodes() uint32 { + return DPESimulatorMaxTCINodes +} + +// GetProfileMajorVersion gets the major profile version supported by this DPE +func (s *DpeSimulator) GetProfileMajorVersion() uint16 { + return DPESimulatorMajorProfileVersion +} + +// GetProfileMinorVersion gets the minor profile version supported by this DPE +func (s *DpeSimulator) GetProfileMinorVersion() uint16 { + return DPESimulatorMinorProfileVersion +} + +// GetProfileVendorID gets the vendor ID of this DPE +func (s *DpeSimulator) GetProfileVendorID() uint32 { + return DPESimulatorVendorID +} + +// GetProfileVendorSku gets the vendor SKU of this DPE +func (s *DpeSimulator) GetProfileVendorSku() uint32 { + return DPESimulatorVendorSKU +} diff --git a/verification/testing/go.mod b/verification/testing/go.mod index c7e1f1c3..44489ac4 100644 --- a/verification/testing/go.mod +++ b/verification/testing/go.mod @@ -4,8 +4,11 @@ go 1.20 replace github.com/chipsalliance/caliptra-dpe/verification/client => ../client +replace github.com/chipsalliance/caliptra-dpe/verification/sim => ../sim + require ( - github.com/chipsalliance/caliptra-dpe/verification/client v0.0.0-00010101000000-000000000000 + github.com/chipsalliance/caliptra-dpe/verification/client v0.0.0-20240216212309-5c9f6edaeb55 + github.com/chipsalliance/caliptra-dpe/verification/sim v0.0.0-00010101000000-000000000000 github.com/github/smimesign v0.2.0 github.com/google/go-tpm v0.9.0 github.com/google/go-tpm-tools v0.4.1 diff --git a/verification/testing/simulator.go b/verification/testing/simulator.go index fa091d71..04b721e7 100644 --- a/verification/testing/simulator.go +++ b/verification/testing/simulator.go @@ -3,234 +3,21 @@ package verification import ( - "bytes" - "encoding/binary" - "errors" - "io" - "net" - "os" - "os/exec" "reflect" - "syscall" - "time" "github.com/chipsalliance/caliptra-dpe/verification/client" -) - -// Constants for configuring expected values from the DPE simulator -const ( - simulatorSocketPath = "/tmp/dpe-sim.socket" - - DPESimulatorAutoInitLocality uint32 = 0 - DPESimulatorOtherLocality uint32 = 0x4f544852 - DPESimulatorMaxTCINodes uint32 = 24 - DPESimulatorMajorProfileVersion uint16 = client.CurrentProfileMajorVersion - DPESimulatorMinorProfileVersion uint16 = client.CurrentProfileMinorVersion - DPESimulatorVendorID uint32 = 0 - DPESimulatorVendorSKU uint32 = 0 + "github.com/chipsalliance/caliptra-dpe/verification/sim" ) // TargetExe is the simulator executable to use for this test target var TargetExe *string -// DpeSimulator is a handle to a DPE simulator instance -type DpeSimulator struct { - exePath string - cmd *exec.Cmd - supports client.Support - currentLocality uint32 - isInitialized bool - client.Transport -} - -// HasPowerControl returns whether the simulator can be started and stopped. -func (s *DpeSimulator) HasPowerControl() bool { - return true -} - -// PowerOn starts the simulator. -func (s *DpeSimulator) PowerOn() error { - args := []string{} - if s.supports.Simulation { - args = append(args, "--supports-simulation") - } - if s.supports.Recursive { - args = append(args, "--supports-recursive") - } - if s.supports.AutoInit { - args = append(args, "--supports-auto-init") - } - 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") - } - if s.supports.RetainParentContext { - args = append(args, "--supports-retain-parent-context") - } - - s.cmd = exec.Command(s.exePath, 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 -} - -// PowerOff kills the simulator in a way that it can cleanup before closing. -func (s *DpeSimulator) 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 simulator never stopped") - } - } - return nil -} - -// Wait for the simulator to come alive. Timeout at 15 seconds. -func (s *DpeSimulator) waitForPower(on bool) bool { - timeoutSeconds := 15 - checksPerSec := 50 - - for i := 0; i < checksPerSec*timeoutSeconds; i++ { - // Check if the socket file has been created. - if fileExists(simulatorSocketPath) == on { - return true - } - time.Sleep(time.Duration(1000/checksPerSec) * time.Millisecond) - } - return false -} - -func fileExists(filename string) bool { - info, err := os.Stat(filename) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -} - -// SendCmd sends a DPE command to the simulator -func (s *DpeSimulator) 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. - numSent, err := conn.Write(prepended.Bytes()) - if err != nil { - return nil, err - } - if numSent != len(prepended.Bytes()) { - return nil, errors.New("didn't send the whole command") - } - - // Get the response. - return io.ReadAll(conn) -} - -// GetSupport gets supported DPE features from the simulator -func (s *DpeSimulator) GetSupport() *client.Support { - return &s.supports -} - -// GetIsInitialized gets whether DPE is initialized -func (s *DpeSimulator) GetIsInitialized() bool { - return s.supports.AutoInit || s.isInitialized -} - -// SetIsInitialized sets whether DPE is initialized -func (s *DpeSimulator) SetIsInitialized(isInitialized bool) { - s.isInitialized = isInitialized -} - -// GetSupportedLocalities gets the list of localities the simulator supports -func (s *DpeSimulator) GetSupportedLocalities() []uint32 { - return []uint32{DPESimulatorAutoInitLocality, DPESimulatorOtherLocality} -} - -// HasLocalityControl returns whether the simulator can artificially set the -// locality of the caller. The simulator target can always control the locality. -func (s *DpeSimulator) HasLocalityControl() bool { - return true -} - -// SetLocality sets the locality of this caller -func (s *DpeSimulator) SetLocality(locality uint32) { - s.currentLocality = locality -} - -// GetLocality gets the locality of the current caller -func (s *DpeSimulator) GetLocality() uint32 { - return s.currentLocality -} - -// GetMaxTciNodes gets the max number of TCI nodes the DPE supports -func (s *DpeSimulator) GetMaxTciNodes() uint32 { - return DPESimulatorMaxTCINodes -} - -// GetProfileMajorVersion gets the major profile version supported by this DPE -func (s *DpeSimulator) GetProfileMajorVersion() uint16 { - return DPESimulatorMajorProfileVersion -} - -// GetProfileMinorVersion gets the minor profile version supported by this DPE -func (s *DpeSimulator) GetProfileMinorVersion() uint16 { - return DPESimulatorMinorProfileVersion -} - -// GetProfileVendorID gets the vendor ID of this DPE -func (s *DpeSimulator) GetProfileVendorID() uint32 { - return DPESimulatorVendorID -} - -// GetProfileVendorSku gets the vendor SKU of this DPE -func (s *DpeSimulator) GetProfileVendorSku() uint32 { - return DPESimulatorVendorSKU -} - // GetSimulatorTarget gets the simulator target func GetSimulatorTarget(supportNeeded []string, targetExe string) client.TestDPEInstance { - value := reflect.ValueOf(DpeSimulator{}.supports) + value := reflect.ValueOf(client.Support{}) fields := reflect.Indirect(value) - fVal := reflect.New(reflect.TypeOf(DpeSimulator{}.supports)) + fVal := reflect.New(reflect.TypeOf(client.Support{})) for i := 0; i < len(supportNeeded); i++ { for j := 0; j < value.NumField(); j++ { @@ -240,8 +27,8 @@ func GetSimulatorTarget(supportNeeded []string, targetExe string) client.TestDPE } } support := fVal.Elem().Interface().(client.Support) - var instance client.TestDPEInstance = &DpeSimulator{exePath: targetExe, supports: support} - return instance + simulator := sim.NewSimulator(targetExe, support) + return &simulator } // GetSimulatorTargets gets different simulator targets with different support @@ -384,6 +171,6 @@ func GetSimulatorTargets() []TestTarget { // Get the test target for simulator/emulator func getTestTarget(supportNeeded []string) client.TestDPEInstance { instance := GetSimulatorTarget(supportNeeded, *TargetExe) - instance.SetLocality(DPESimulatorAutoInitLocality) + instance.SetLocality(sim.DPESimulatorAutoInitLocality) return instance }