diff --git a/cmd/get-measurements/main.go b/cmd/get-measurements/main.go index 0761507..556b76a 100644 --- a/cmd/get-measurements/main.go +++ b/cmd/get-measurements/main.go @@ -14,7 +14,9 @@ package main // // go run cmd/get-measurements/main.go --addr=https://instance_ip:port --out-measurements=measurements.json --out-response=response.txt // -// You can also compare the resulting measurements with a list of expected measurements. +// You can also compare the resulting measurements with a list of expected measurements: +// +// go run cmd/get-measurements/main.go --addr=https://instance_ip:port --expected-measurements measurements.json // import ( @@ -31,6 +33,7 @@ import ( "github.com/flashbots/cvm-reverse-proxy/common" "github.com/flashbots/cvm-reverse-proxy/internal/atls" "github.com/flashbots/cvm-reverse-proxy/internal/attestation/variant" + "github.com/flashbots/cvm-reverse-proxy/multimeasurements" "github.com/flashbots/cvm-reverse-proxy/proxy" "github.com/urfave/cli/v2" // imports as package "cli" ) @@ -97,10 +100,10 @@ func runClient(cCtx *cli.Context) (err error) { } // Load expected measurements from file or URL (if provided) - var expectedMeasurements *common.ExpectedMeasurements + var expectedMeasurements *multimeasurements.MultiMeasurements if expectedMeasurementsPath != "" { log.Info("Loading expected measurements from " + expectedMeasurementsPath + " ...") - expectedMeasurements, err = common.NewExpectedMeasurementsFromFile(expectedMeasurementsPath) + expectedMeasurements, err = multimeasurements.New(expectedMeasurementsPath) if err != nil { return err } @@ -167,7 +170,7 @@ func runClient(cCtx *cli.Context) (err error) { if expectedMeasurements != nil { found, foundMeasurement := expectedMeasurements.Contains(extractedMeasurements) if found { - log.Info("Measurements match expected measurements for " + foundMeasurement.MeasurementID + " ✅") + log.With("matchedMeasurements", foundMeasurement.MeasurementID).Info("Measurements match expected measurements ✅") } else { log.Error("Measurements do not match expected measurements! ❌") } diff --git a/common/expected_measurements.go b/multimeasurements/multimeasurements.go similarity index 59% rename from common/expected_measurements.go rename to multimeasurements/multimeasurements.go index 4a0bbf1..28ab9df 100644 --- a/common/expected_measurements.go +++ b/multimeasurements/multimeasurements.go @@ -1,26 +1,9 @@ -package common - -// -// Helper to load expected measurements from a file or URL, and compare -// provided measurements against them. -// -// Compatible with measurements data schema v2 (see measurements.json) -// as well as the legacy v1 schema. -// -// [ -// { -// "measurement_id": "cvm-image-azure-tdx.rootfs-20241107200854.wic.vhd", -// "attestation_type": "azure-tdx", -// "measurements": { -// "4": { -// "expected": "1b8cd655f5ebdf50bedabfb5db6b896a0a7c56de54f318103a2de1e7cea57b6b" -// }, -// ... -// } -// }, -// ... -// ] +// Package multimeasurements contains a helper to load a file with multiple measurements +// and compare provided measurements against them. // +// Compatible with measurements data schema v2 (see measurements.json) as well as the +// legacy v1 schema. +package multimeasurements import ( "bytes" @@ -33,9 +16,9 @@ import ( "github.com/flashbots/cvm-reverse-proxy/internal/attestation/measurements" ) -// ExpectedMeasurements is a struct that represents a list of expected measurements, -// and allows checking if given measurements matches a known one. -type ExpectedMeasurements struct { +// MultiMeasurements is holds several known measurements, and can check if a +// given measurements matches a known one. +type MultiMeasurements struct { Measurements []MeasurementsContainer } @@ -45,11 +28,11 @@ type MeasurementsContainer struct { Measurements measurements.M `json:"measurements"` } -type LegacyMeasurementsContainer map[string]measurements.M +type LegacyMultiMeasurements map[string]measurements.M -// NewExpectedMeasurementsFromFile returns an ExpectedMeasurements instance, -// with the measurements loaded from a file or URL. -func NewExpectedMeasurementsFromFile(path string) (m *ExpectedMeasurements, err error) { +// New returns a MultiMeasurements instance, with the measurements +// loaded from a file or URL. +func New(path string) (m *MultiMeasurements, err error) { var data []byte if strings.HasPrefix(path, "http") { // load from URL @@ -70,11 +53,11 @@ func NewExpectedMeasurementsFromFile(path string) (m *ExpectedMeasurements, err } } - m = &ExpectedMeasurements{} + m = &MultiMeasurements{} // Try to load the v2 data schema, if that fails fall back to legacy v1 schema if err = json.Unmarshal(data, &m.Measurements); err != nil { - var legacyData LegacyMeasurementsContainer + var legacyData LegacyMultiMeasurements err = json.Unmarshal(data, &legacyData) for measurementID, measurements := range legacyData { container := MeasurementsContainer{ @@ -91,7 +74,7 @@ func NewExpectedMeasurementsFromFile(path string) (m *ExpectedMeasurements, err // Contains checks if the provided measurements match one of the known measurements. Any keys in the provided // measurements which are not in the known measurements are ignored. -func (m *ExpectedMeasurements) Contains(measurements map[uint32][]byte) (found bool, foundMeasurement *MeasurementsContainer) { +func (m *MultiMeasurements) Contains(measurements map[uint32][]byte) (found bool, foundMeasurement *MeasurementsContainer) { // For every known container, all known measurements match (and additional ones are ignored) for _, container := range m.Measurements { allMatch := true diff --git a/common/expected_measurements_test.go b/multimeasurements/multimeasurements_test.go similarity index 93% rename from common/expected_measurements_test.go rename to multimeasurements/multimeasurements_test.go index b13d066..8cc6a50 100644 --- a/common/expected_measurements_test.go +++ b/multimeasurements/multimeasurements_test.go @@ -1,4 +1,4 @@ -package common +package multimeasurements import ( "encoding/hex" @@ -23,10 +23,10 @@ func mustBytesFromHex(hexValue string) []byte { // Measurements V1 (legacy) JSON (from https://github.com/flashbots/cvm-reverse-proxy/blob/837588b9f87ee49d1bb6dca4712a1c2844eb1ecc/measurements.json) var measurementsV1JSON = []byte(`{"azure-tdx-example":{"11":{"expected":"efa43e0beff151b0f251c4abf48152382b1452b4414dbd737b4127de05ca31f7"},"12":{"expected":"0000000000000000000000000000000000000000000000000000000000000000"},"13":{"expected":"0000000000000000000000000000000000000000000000000000000000000000"},"15":{"expected":"0000000000000000000000000000000000000000000000000000000000000000"},"4":{"expected":"ea92ff762767eae6316794f1641c485d4846bc2b9df2eab6ba7f630ce6f4d66f"},"8":{"expected":"0000000000000000000000000000000000000000000000000000000000000000"},"9":{"expected":"c9f429296634072d1063a03fb287bed0b2d177b0a504755ad9194cffd90b2489"}},"dcap-tdx-example":{"0":{"expected":"5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2"},"1":{"expected":"4216e925f796f4e282cfa6e72d4c77a80560987afa29155a61fdc33adb80eab0d4112abd52387e5e25a60deefb8a5287"},"2":{"expected":"4274fefb79092c164000b571b64ecb432fa2357adb421fd1c77a867168d7d7f7fe82796d1eba092c7bab35cf43f5ec55"},"3":{"expected":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},"4":{"expected":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}}`) -// TestExpectedMeasurementsV2 tests the v2 data schema -func TestExpectedMeasurementsV2(t *testing.T) { +// TestMultiMeasurementsV2 tests the v2 data schema +func TestMultiMeasurementsV2(t *testing.T) { // Load expected measurements from JSON file (in V2 format) - m, err := NewExpectedMeasurementsFromFile("../measurements.json") + m, err := New("../measurements.json") require.NoError(t, err) require.Len(t, m.Measurements, 3) @@ -71,13 +71,13 @@ func TestExpectedMeasurementsV2(t *testing.T) { require.Equal(t, "dcap-tdx-example-02", foundMeasurement.MeasurementID) } -func TestExpectedMeasurementsV1(t *testing.T) { +func TestMultiMeasurementsV1(t *testing.T) { tempDir := t.TempDir() err := os.WriteFile(filepath.Join(tempDir, "measurements.json"), measurementsV1JSON, 0644) require.NoError(t, err) // Load expected measurements from JSON file - m, err := NewExpectedMeasurementsFromFile(filepath.Join(tempDir, "measurements.json")) + m, err := New(filepath.Join(tempDir, "measurements.json")) require.NoError(t, err) require.Len(t, m.Measurements, 2) diff --git a/proxy/atls_config.go b/proxy/atls_config.go index 1441345..eee5fb2 100644 --- a/proxy/atls_config.go +++ b/proxy/atls_config.go @@ -10,13 +10,13 @@ import ( "log/slog" "os" - "github.com/flashbots/cvm-reverse-proxy/common" "github.com/flashbots/cvm-reverse-proxy/internal/atls" azure_tdx "github.com/flashbots/cvm-reverse-proxy/internal/attestation/azure/tdx" "github.com/flashbots/cvm-reverse-proxy/internal/attestation/measurements" "github.com/flashbots/cvm-reverse-proxy/internal/attestation/variant" "github.com/flashbots/cvm-reverse-proxy/internal/cloud/cloudprovider" "github.com/flashbots/cvm-reverse-proxy/internal/config" + "github.com/flashbots/cvm-reverse-proxy/multimeasurements" dcap_tdx "github.com/flashbots/cvm-reverse-proxy/tdx" ) @@ -66,7 +66,7 @@ func CreateAttestationValidators(log *slog.Logger, attestationType AttestationTy return nil, err } - var parsedMeasurements []common.MeasurementsContainer + var parsedMeasurements []multimeasurements.MeasurementsContainer err = json.Unmarshal(jsonMeasurements, &parsedMeasurements) if err != nil { return nil, err