diff --git a/cmd/veil-verify/main.go b/cmd/veil-verify/main.go index ea5d69a..9d59f4c 100644 --- a/cmd/veil-verify/main.go +++ b/cmd/veil-verify/main.go @@ -10,6 +10,7 @@ import ( "net/http" "os" "os/signal" + "strings" "github.com/Amnesic-Systems/veil/internal/enclave" "github.com/Amnesic-Systems/veil/internal/enclave/nitro" @@ -22,6 +23,7 @@ import ( type config struct { Addr string Testing bool + PCRs enclave.PCR } func parseFlags(out io.Writer, args []string) (*config, error) { @@ -33,6 +35,11 @@ func parseFlags(out io.Writer, args []string) (*config, error) { "", "Address of the enclave, e.g.: https://example.com:8443", ) + msmts := fs.String( + "measurements", + "", + "JSON-encoded enclave image measurements", + ) testing := fs.Bool( "insecure", false, @@ -43,9 +50,53 @@ func parseFlags(out io.Writer, args []string) (*config, error) { return nil, fmt.Errorf("failed to parse flags: %w", err) } + pcr, err := toPCR([]byte(*msmts)) + if err != nil { + return nil, err + } + return &config{ Addr: *addr, Testing: *testing, + PCRs: pcr, + }, nil +} + +func toPCR(jsonMsmts []byte) (enclave.PCR, error) { + // This structs represents the JSON-encoded measurements of the enclave image. + // The JSON tags must match the output of the nitro-cli command line tool. An + // example: + // + // { + // "Measurements": { + // "HashAlgorithm": "Sha384 { ... }", + // "PCR0": "8b927cf0bbf2d668a8c24c69afd23bff2dda713b4f0d70195205950f9a5a1fbb7089ad937e3025ee8d5a084f3d6c9126", + // "PCR1": "4b4d5b3661b3efc12920900c80e126e4ce783c522de6c02a2a5bf7af3a2b9327b86776f188e4be1c1c404a129dbda493", + // "PCR2": "22d2194eb27a7cda42e66dd5b91ef13e5a153d797c04ae179e59bef1c93438d6ad0365c175c119230e36d0f8d6b6b59e" + // } + // } + m := struct { + Measurements struct { + HashAlgorithm string `json:"HashAlgorithm"` + PCR0 string `json:"PCR0"` + PCR1 string `json:"PCR1"` + PCR2 string `json:"PCR2"` + } `json:"Measurements"` + }{} + if err := json.Unmarshal(jsonMsmts, &m); err != nil { + return nil, err + } + + const want = "sha384" + got := strings.ToLower(m.Measurements.HashAlgorithm) + if !strings.HasPrefix(got, want) { + return nil, fmt.Errorf("expected hash algorithm %q but got %q", want, got) + } + + return enclave.PCR{ + 0: []byte(m.Measurements.PCR0), + 1: []byte(m.Measurements.PCR1), + 2: []byte(m.Measurements.PCR2), }, nil } @@ -95,8 +146,8 @@ func attestEnclave(ctx context.Context, cfg *config) (err error) { return err } defer resp.Body.Close() - var doc enclave.RawDocument - if err := json.Unmarshal(body, &doc); err != nil { + var rawDoc enclave.RawDocument + if err := json.Unmarshal(body, &rawDoc); err != nil { return err } @@ -105,7 +156,12 @@ func attestEnclave(ctx context.Context, cfg *config) (err error) { if cfg.Testing { attester = noop.NewAttester() } - _, err = attester.Verify(&doc, nonce) + doc, err := attester.Verify(&rawDoc, nonce) + + if !cfg.PCRs.Equal(doc.PCRs) { + fmt.Println("NOT EQUAL") + } + return err } diff --git a/internal/enclave/attester.go b/internal/enclave/attester.go index e5c632b..fa435df 100644 --- a/internal/enclave/attester.go +++ b/internal/enclave/attester.go @@ -25,7 +25,7 @@ type Document struct { ModuleID string `cbor:"module_id" json:"module_id"` Timestamp uint64 `cbor:"timestamp" json:"timestamp"` Digest string `cbor:"digest" json:"digest"` - PCRs pcr `cbor:"pcrs" json:"pcrs"` + PCRs PCR `cbor:"pcrs" json:"pcrs"` Certificate []byte `cbor:"certificate" json:"certificate"` CABundle [][]byte `cbor:"cabundle" json:"cabundle"` AuxInfo diff --git a/internal/enclave/pcr.go b/internal/enclave/pcr.go index d4925ed..25938a6 100644 --- a/internal/enclave/pcr.go +++ b/internal/enclave/pcr.go @@ -7,12 +7,12 @@ import ( var emptyPCR = make([]byte, sha512.Size384) -// pcr represents the enclave's platform configuration register (PCR) values. -type pcr map[uint][]byte +// PCR represents the enclave's platform configuration register (PCR) values. +type PCR map[uint][]byte // FromDebugMode returns true if the given PCR map was generated by an enclave // in debug mode. -func (p pcr) FromDebugMode() bool { +func (p PCR) FromDebugMode() bool { // PCRs 0, 1, and 2 are set at compile time but will be unset if the enclave // is running in debug mode. return bytes.Equal(p[0], emptyPCR) && @@ -21,7 +21,7 @@ func (p pcr) FromDebugMode() bool { } // Equal returns true if (and only if) the two given PCR maps are identical. -func (ours pcr) Equal(theirs pcr) bool { +func (ours PCR) Equal(theirs PCR) bool { if len(ours) != len(theirs) { return false } diff --git a/internal/enclave/pcr_test.go b/internal/enclave/pcr_test.go index 356d247..e986447 100644 --- a/internal/enclave/pcr_test.go +++ b/internal/enclave/pcr_test.go @@ -10,16 +10,16 @@ import ( func TestPCRsFromDebugMode(t *testing.T) { cases := []struct { name string - pcrs pcr + pcrs PCR want bool }{ { name: "empty", - pcrs: pcr{}, + pcrs: PCR{}, }, { name: "debug mode", - pcrs: pcr{ + pcrs: PCR{ 0: emptyPCR, 1: emptyPCR, 2: emptyPCR, @@ -30,7 +30,7 @@ func TestPCRsFromDebugMode(t *testing.T) { }, { name: "not debug mode", - pcrs: pcr{ + pcrs: PCR{ 0: []byte("foo"), 1: emptyPCR, 2: emptyPCR, @@ -48,43 +48,43 @@ func TestPCRsFromDebugMode(t *testing.T) { func TestPCRsEqual(t *testing.T) { cases := []struct { name string - pcr1 pcr - pcr2 pcr + pcr1 PCR + pcr2 PCR want bool }{ { name: "empty", - pcr1: pcr{}, - pcr2: pcr{}, + pcr1: PCR{}, + pcr2: PCR{}, want: true, }, { name: "identical", - pcr1: pcr{ + pcr1: PCR{ 1: []byte("foobar"), }, - pcr2: pcr{ + pcr2: PCR{ 1: []byte("foobar"), }, want: true, }, { name: "PCR mismatch", - pcr1: pcr{ + pcr1: PCR{ 1: []byte("foobar"), }, - pcr2: pcr{ + pcr2: PCR{ 1: []byte("barfoo"), }, want: false, }, { name: "ignore PCR4", - pcr1: pcr{ + pcr1: PCR{ 1: []byte("foobar"), 4: []byte("foo"), }, - pcr2: pcr{ + pcr2: PCR{ 1: []byte("foobar"), 4: []byte("bar"), }, @@ -92,21 +92,21 @@ func TestPCRsEqual(t *testing.T) { }, { name: "length mismatch", - pcr1: pcr{ + pcr1: PCR{ 1: []byte("foobar"), 2: []byte("foo"), }, - pcr2: pcr{ + pcr2: PCR{ 1: []byte("foobar"), }, want: false, }, { name: "PCR index mismatch", - pcr1: pcr{ + pcr1: PCR{ 1: []byte("foo"), }, - pcr2: pcr{ + pcr2: PCR{ 2: []byte("foo"), }, want: false,