diff --git a/cmd/veil/main_test.go b/cmd/veil/main_test.go index ea32314..f9aecf0 100644 --- a/cmd/veil/main_test.go +++ b/cmd/veil/main_test.go @@ -268,9 +268,12 @@ func TestAttestation(t *testing.T) { var a enclave.AttestationDoc require.NoError(t, json.Unmarshal(body, &a)) - // "Verify" the attestation document using our noop attester. + // Verify the attestation document. We expect no error but if the + // test is run inside a Nitro Enclave, we will get ErrDebugMode. aux, err := attester.Verify(&a, c.nonce) - require.NoError(t, err, errFromBody(t, resp)) + if err != nil { + require.ErrorIs(t, err, nitro.ErrDebugMode, errFromBody(t, resp)) + } // Ensure that the recovered nonce matches what we sent. n, err := attestation.GetNonce(aux) diff --git a/internal/enclave/nitro/attester.go b/internal/enclave/nitro/attester.go index e56c31c..bc096eb 100644 --- a/internal/enclave/nitro/attester.go +++ b/internal/enclave/nitro/attester.go @@ -13,6 +13,7 @@ import ( ) var _ enclave.Attester = (*Attester)(nil) +var ErrDebugMode = errors.New("attestation document was produced in debug mode") // Attester implements the attester interface by drawing on the AWS Nitro // Enclave hypervisor. @@ -102,8 +103,6 @@ func (a *Attester) Verify( return nil, err } - // TODO: return an error if the attestation mode was produced in debug mode. - // Verify that the attestation document contains the nonce that we may have // asked it to embed. if ourNonce != nil { @@ -116,9 +115,15 @@ func (a *Attester) Verify( } } + // If the enclave is running in debug mode, return an error *and* the + // auxiliary information. + if res.Document.PCRs.FromDebugMode() { + err = ErrDebugMode + } + return &enclave.AuxInfo{ Nonce: convertFrom(res.Document.Nonce), UserData: convertFrom(res.Document.UserData), PublicKey: convertFrom(res.Document.PublicKey), - }, nil + }, err } diff --git a/internal/enclave/nitro/pcr.go b/internal/enclave/nitro/pcr.go index 8b0ffc4..fc14ea6 100644 --- a/internal/enclave/nitro/pcr.go +++ b/internal/enclave/nitro/pcr.go @@ -2,11 +2,14 @@ package nitro import ( "bytes" + "crypto/sha512" "github.com/Amnesic-Systems/veil/internal/enclave" "github.com/Amnesic-Systems/veil/internal/errs" ) +var emptyPCR = make([]byte, sha512.Size384) + // pcr represents the enclave's platform configuration register (PCR) values. type pcr map[uint][]byte @@ -27,6 +30,16 @@ func getPCRs() (_ pcr, err error) { return pcr(res.Document.PCRs), nil } +// FromDebugMode returns true if the given PCR map was generated by an enclave +// in debug mode. +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) && + bytes.Equal(p[1], emptyPCR) && + bytes.Equal(p[2], emptyPCR) +} + // Equal returns true if (and only if) the two given PCR maps are identical. func (ours pcr) Equal(theirs pcr) bool { // PCR4 contains a hash over the parent's instance ID. Our enclaves run diff --git a/internal/enclave/nitro/pcr_test.go b/internal/enclave/nitro/pcr_test.go index 30da23c..c9161e8 100644 --- a/internal/enclave/nitro/pcr_test.go +++ b/internal/enclave/nitro/pcr_test.go @@ -27,6 +27,44 @@ func TestGetPCRs(t *testing.T) { require.Equal(t, pcrs1, pcrs2) } +func TestPCRsFromDebugMode(t *testing.T) { + cases := []struct { + name string + pcrs pcr + want bool + }{ + { + name: "empty", + pcrs: pcr{}, + }, + { + name: "debug mode", + pcrs: pcr{ + 0: emptyPCR, + 1: emptyPCR, + 2: emptyPCR, + 3: []byte("foo"), // Should be ignored. + 4: []byte("bar"), // Should be ignored. + }, + want: true, + }, + { + name: "not debug mode", + pcrs: pcr{ + 0: []byte("foo"), + 1: emptyPCR, + 2: emptyPCR, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + require.Equal(t, c.want, c.pcrs.FromDebugMode()) + }) + } +} + func TestPCRsEqual(t *testing.T) { cases := []struct { name string diff --git a/internal/service/attestation/aux_test.go b/internal/service/attestation/aux_test.go index 6d13acb..494db37 100644 --- a/internal/service/attestation/aux_test.go +++ b/internal/service/attestation/aux_test.go @@ -130,8 +130,12 @@ func TestBuilder(t *testing.T) { doc, err := b.Attest(c.attestFields...) require.NoError(t, err) + // Verify the attestation document. We expect no error but if the + // test is run inside a Nitro Enclave, we will get ErrDebugMode. aux, err := attester.Verify(doc, nil) - require.NoError(t, err) + if err != nil { + require.ErrorIs(t, err, nitro.ErrDebugMode) + } require.Equal(t, c.wantAux, aux) }) }