diff --git a/go.mod b/go.mod index 65c93232..401aa40a 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,14 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/denisbrodbeck/machineid v1.0.1 + github.com/fatih/color v1.13.0 github.com/gin-gonic/gin v1.8.1 github.com/go-playground/assert/v2 v2.0.1 github.com/golang/mock v1.6.0 + github.com/golang/protobuf v1.5.2 github.com/google/go-tpm v0.3.3 github.com/google/uuid v1.3.0 + github.com/hashicorp/go-hclog v1.2.0 github.com/hashicorp/go-plugin v1.4.4 github.com/jellydator/ttlcache/v3 v3.0.0 github.com/mattn/go-sqlite3 v1.14.14 @@ -18,10 +21,12 @@ require ( github.com/moogar0880/problems v0.1.1 github.com/olekukonko/tablewriter v0.0.5 github.com/open-policy-agent/opa v0.43.1 + github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 github.com/spf13/cobra v1.5.0 github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.9.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 + github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20221128190504-3eeb9fee39cb github.com/veraison/corim v0.0.0-20220801100627-a48aacbd333c github.com/veraison/dice v0.0.1 github.com/veraison/eat v0.0.0-20210331113810-3da8a4dd42ff @@ -37,7 +42,6 @@ require ( github.com/agnivade/levenshtein v1.0.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect - github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect @@ -47,8 +51,7 @@ require ( github.com/go-playground/validator/v10 v10.10.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.9.7 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/hashicorp/go-hclog v1.2.0 // indirect + github.com/golang/glog v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect @@ -65,12 +68,12 @@ require ( github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect + github.com/mitchellh/protoc-gen-go-json v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect diff --git a/go.sum b/go.sum index de6da40a..3dab069f 100644 --- a/go.sum +++ b/go.sum @@ -778,6 +778,8 @@ github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/protoc-gen-go-json v1.1.0 h1:lEi1xtXyYKDwA8EB5u27+UUZOTznC4JpqVOKZwCGJUo= +github.com/mitchellh/protoc-gen-go-json v1.1.0/go.mod h1:pACAKlMtBf4SMFbVswcjwNwWwlci6Vn841H5jPRcE9I= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= @@ -1022,6 +1024,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1033,6 +1036,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -1055,6 +1060,12 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser/v2 v2.4.6 h1:Yjzp66g6oVq93Jihbi0qhGnf/6zIWjcm8H6gA27zstE= github.com/vektah/gqlparser/v2 v2.4.6/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20220902142425-b49cd6e96cf5 h1:TamshIh803Xw8wEYgIuqRQjbUfaMSHMDsMtBH4TOpzw= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20220902142425-b49cd6e96cf5/go.mod h1:EXpO454Q3yOKVoNc7ECuLRfP7cmTmuhPwtuFYbkxWBk= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20221112151611-0893a6c14411 h1:QHBX9m8HlqC+qhc/gGLdHA+8hfwsNY/s8lBiVnzAde0= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20221112151611-0893a6c14411/go.mod h1:JRldyv/2U+D7c5yI1HP9iY/Aa7j3TnhwpUvC1ZwE+Lw= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20221128190504-3eeb9fee39cb h1:wveFlH73+Tqm5NM9nSGoyeTnU4JsH5ARcrcETMD+T3M= +github.com/veracruz-project/go-nitro-enclave-attestation-document v0.0.0-20221128190504-3eeb9fee39cb/go.mod h1:JRldyv/2U+D7c5yI1HP9iY/Aa7j3TnhwpUvC1ZwE+Lw= github.com/veraison/apiclient v0.0.2/go.mod h1:H8YDx1ixM24GYP/aLbhq+HJsej0lVUqFCRIL5Uu4B0o= github.com/veraison/corim v0.0.0-20220801100627-a48aacbd333c h1:+qOmTV5aI475VuNXDfy8Klg8m2ovSISmdZlS63w0J64= github.com/veraison/corim v0.0.0-20220801100627-a48aacbd333c/go.mod h1:FOUHHZ7fOyWKk4oKUjO5Zw5gnkjz0rtzcJDvUZZFRSg= diff --git a/proto/attestation_format.pb.go b/proto/attestation_format.pb.go index bbe70628..33dab3bf 100644 --- a/proto/attestation_format.pb.go +++ b/proto/attestation_format.pb.go @@ -34,6 +34,8 @@ const ( AttestationFormat_TCG_DICE AttestationFormat = 2 // TPM EnactTrust AttestationFormat_TPM_ENACTTRUST AttestationFormat = 3 + // AWS Nitro Enclaves + AttestationFormat_AWS_NITRO AttestationFormat = 4 ) // Enum value maps for AttestationFormat. @@ -43,12 +45,14 @@ var ( 1: "PSA_IOT", 2: "TCG_DICE", 3: "TPM_ENACTTRUST", + 4: "AWS_NITRO", } AttestationFormat_value = map[string]int32{ "UNKNOWN_FORMAT": 0, "PSA_IOT": 1, "TCG_DICE": 2, "TPM_ENACTTRUST": 3, + "AWS_NITRO": 4, } ) @@ -84,15 +88,16 @@ var File_attestation_format_proto protoreflect.FileDescriptor var file_attestation_format_proto_rawDesc = []byte{ 0x0a, 0x18, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2a, 0x56, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x6f, 0x2a, 0x65, 0x0a, 0x11, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x53, 0x41, 0x5f, 0x49, 0x4f, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x43, 0x47, 0x5f, 0x44, 0x49, 0x43, 0x45, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x50, 0x4d, 0x5f, 0x45, 0x4e, 0x41, - 0x43, 0x54, 0x54, 0x52, 0x55, 0x53, 0x54, 0x10, 0x03, 0x42, 0x24, 0x5a, 0x22, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x69, 0x73, 0x6f, 0x6e, - 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x43, 0x54, 0x54, 0x52, 0x55, 0x53, 0x54, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x57, 0x53, + 0x5f, 0x4e, 0x49, 0x54, 0x52, 0x4f, 0x10, 0x04, 0x42, 0x24, 0x5a, 0x22, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x69, 0x73, 0x6f, 0x6e, 0x2f, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/attestation_format.proto b/proto/attestation_format.proto index 2f11ef51..dc91631e 100644 --- a/proto/attestation_format.proto +++ b/proto/attestation_format.proto @@ -18,5 +18,8 @@ enum AttestationFormat { // TPM EnactTrust TPM_ENACTTRUST = 3; + + // AWS Nitro Enclaves + AWS_NITRO = 4; } diff --git a/provisioning/plugins/Makefile b/provisioning/plugins/Makefile index ce87dbba..cfda8df0 100644 --- a/provisioning/plugins/Makefile +++ b/provisioning/plugins/Makefile @@ -4,5 +4,6 @@ SUBDIR += common SUBDIR += corim-psa-decoder SUBDIR += corim-tpm-enacttrust-decoder +SUBDIR += corim-nitro-decoder include ../../mk/subdir.mk diff --git a/provisioning/plugins/corim-nitro-decoder/Makefile b/provisioning/plugins/corim-nitro-decoder/Makefile new file mode 100644 index 00000000..42b810cf --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/Makefile @@ -0,0 +1,15 @@ +# Copyright 2022 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +PLUGIN := ../bin/veraison-provisining-decoder-corim-nitro +GOPKG := github.com/veraison/services/provisioning/plugins/corim-nitro-decoder +SRCS := $(wildcard *.go) + +all-hook-pre all-test-pre all-lint-pre: + $(MAKE) -C ../../../proto protogen + $(MAKE) -C ../../decoder protogen + +include ../../../mk/common.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/README.md b/provisioning/plugins/corim-nitro-decoder/README.md new file mode 100644 index 00000000..836e40f0 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/README.md @@ -0,0 +1,36 @@ +# Endorsement Store Interface + +## Reference Value + +```json +{ + "scheme": "AWS_NITRO", + "type": "REFERENCE_VALUE", + "attributes": { + "nitro.hw-model": "RoadRunner", + "nitro.hw-vendor": "ACME", + "nitro.impl-id": "IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9Ig==", + "nitro.measurement-desc": 1, + "nitro.measurement-type": "BL", + "nitro.measurement-value": "h0KPxSKAPTEGXnvOPPA/5HUJZjHl4Hu9eg/eYMTPJcc=", + "nitro.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "nitro.version": "2.1.0" + } +} +``` + +## Trust Anchor + +```json +{ + "scheme": "AWS_NITRO", + "type": "VERIFICATION_KEY", + "attributes": { + "nitro.hw-model": "RoadRunner", + "nitro.hw-vendor": "ACME", + "nitro.cert": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Vwqe7hy3O8Ypa+BUETLUjBNU3rEXVUyt9XHR7HJWLG7XTKQd9i1kVRXeBPDLFnfYru1/euxRnJM7H9UoFDLdA==", + "nitro.impl-id": "IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9Ig==", + "nitro.inst-id": "AUyj5PUL8kjDl4cCDWj/0FyIdndRvyZFypI/V6mL7NKW" + } +} +``` \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/classattributes.go b/provisioning/plugins/corim-nitro-decoder/classattributes.go new file mode 100644 index 00000000..9d08da42 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/classattributes.go @@ -0,0 +1,40 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "fmt" + + "github.com/veraison/corim/comid" +) + +type NitroClassAttributes struct { + //ImplID []byte + Vendor string + Model string +} + +// extract mandatory ImplID and optional vendor & model +func (o *NitroClassAttributes) FromEnvironment(e comid.Environment) error { + class := e.Class + + if class == nil { + return fmt.Errorf("expecting class in environment") + } + + classID := class.ClassID + + if classID == nil { + return fmt.Errorf("expecting class-id in class") + } + + if class.Vendor != nil { + o.Vendor = *class.Vendor + } + + if class.Model != nil { + o.Model = *class.Model + } + + return nil +} \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/decoder.go b/provisioning/plugins/corim-nitro-decoder/decoder.go new file mode 100644 index 00000000..901a48d6 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/decoder.go @@ -0,0 +1,38 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "github.com/veraison/services/provisioning/decoder" + plugin_common "github.com/veraison/services/provisioning/plugins/common" +) + +const ( + SupportedMediaType = "application/corim-unsigned+cbor; profile=http://aws.com/nitro" + PluginName = "unsigned-corim (AWS Nitro profile)" +) + +type Decoder struct{} + +func (o Decoder) Init(params decoder.Params) error { + return nil // no-op +} + +func (o Decoder) Close() error { + return nil // no-op +} + +func (o Decoder) GetName() string { + return PluginName +} + +func (o Decoder) GetSupportedMediaTypes() []string { + return []string{ + SupportedMediaType, + } +} + +func (o Decoder) Decode(data []byte) (*decoder.EndorsementDecoderResponse, error) { + result,err := plugin_common.UnsignedCorimDecoder(data, Extractor{}) + return result, err +} \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/decoder_test.go b/provisioning/plugins/corim-nitro-decoder/decoder_test.go new file mode 100644 index 00000000..ca82a78e --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/decoder_test.go @@ -0,0 +1,109 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/veraison/corim/comid" +) + +func TestDecoder_GetName(t *testing.T) { + d := &Decoder{} + + expected := PluginName + + actual := d.GetName() + + assert.Equal(t, expected, actual) +} + +func TestDecoder_GetSupportedMediaTypes(t *testing.T) { + d := &Decoder{} + + expected := []string{ + SupportedMediaType, + } + + actual := d.GetSupportedMediaTypes() + + assert.Equal(t, expected, actual) +} + +func TestDecoder_Init(t *testing.T) { + d := &Decoder{} + + assert.Nil(t, d.Init(nil)) +} + +func TestDecoder_Close(t *testing.T) { + d := &Decoder{} + + assert.Nil(t, d.Close()) +} + +func TestDecoder_Decode_empty_data(t *testing.T) { + d := &Decoder{} + + emptyData := []byte{} + + expectedErr := `empty data` + + _, err := d.Decode(emptyData) + + assert.EqualError(t, err, expectedErr) +} + +func TestDecoder_Decode_invalid_data(t *testing.T) { + d := &Decoder{} + + invalidCbor := []byte("invalid CBOR") + + expectedErr := `CBOR decoding failed: cbor: cannot unmarshal UTF-8 text string into Go value of type corim.UnsignedCorim` + + _, err := d.Decode(invalidCbor) + + assert.EqualError(t, err, expectedErr) +} + +func TestDecoder_Decode_OK(t *testing.T) { + tvs := []string{ + unsignedCorim, + } + + d := &Decoder{} + + for _, tv := range tvs { + data := comid.MustHexDecode(t, tv) + _, err := d.Decode(data) + assert.NoError(t, err) + } +} + +func TestDecoder_Decode_negative_tests(t *testing.T) { + tvs := []struct { + desc string + input string + expectedErr string + }{ + { + desc: "multiple verification keys", + input: unsignedCorimDualKey, + expectedErr: `bad key in CoMID at index 0: expecting exactly one IAK public key`, + }, + { + desc: "no implementation id specified in the measurement", + input: unsignedCorimNoImplId, + expectedErr: `bad key in CoMID at index 0: could not extract PSA class attributes: expecting class-id in class`, + }, + } + + for _, tv := range tvs { + data := comid.MustHexDecode(t, tv.input) + d := &Decoder{} + _, err := d.Decode(data) + assert.EqualError(t, err, tv.expectedErr) + } +} diff --git a/provisioning/plugins/corim-nitro-decoder/extractor.go b/provisioning/plugins/corim-nitro-decoder/extractor.go new file mode 100644 index 00000000..c0636c57 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/extractor.go @@ -0,0 +1,140 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "errors" + "fmt" + + "github.com/veraison/corim/comid" + "github.com/veraison/services/proto" + structpb "google.golang.org/protobuf/types/known/structpb" +) + +type Extractor struct{} + +func (o Extractor) SwCompExtractor(rv comid.ReferenceValue) ([]*proto.Endorsement, error) { + return nil, fmt.Errorf("Not implemented, not needed?") + // var nitroClassAttrs NitroClassAttributes + + // if err := nitroClassAttrs.FromEnvironment(rv.Environment); err != nil { + // return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) + // } + + // // Each measurement is encoded in a measurement-map of a CoMID + // // reference-triple-record. Since a measurement-map can encode one or more + // // measurements, a single reference-triple-record can carry as many + // // measurements as needed, provided they belong to the same PSA RoT + // // identified in the subject of the "reference value" triple. A single + // // reference-triple-record SHALL completely describe the updatable PSA RoT. + // swComponents := make([]*proto.Endorsement, 0, len(rv.Measurements)) + + // for i, m := range rv.Measurements { + // var nitroSwCompAttrs NitroSwCompAttributes + + // if err := nitroSwCompAttrs.FromMeasurement(m); err != nil { + // return nil, fmt.Errorf("extracting measurement at index %d: %w", i, err) + // } + + // swAttrs, err := makeSwAttrs(nitroClassAttrs, nitroSwCompAttrs) + // if err != nil { + // return nil, fmt.Errorf("failed to create software component attributes: %w", err) + // } + + // swComponent := proto.Endorsement{ + // Scheme: proto.AttestationFormat_AWS_NITRO, + // Type: proto.EndorsementType_REFERENCE_VALUE, + // Attributes: swAttrs, + // } + + // swComponents = append(swComponents, &swComponent) + // } + + // if len(swComponents) == 0 { + // return nil, fmt.Errorf("no software components found") + // } + + // return swComponents, nil +} + +func makeSwAttrs(c NitroClassAttributes, s NitroSwCompAttributes) (*structpb.Struct, error) { + return nil, fmt.Errorf("Not implemented, not needed?") + // swAttrs := map[string]interface{}{ + // //"psa.impl-id": c.ImplID, + // "psa.signer-id": s.SignerID, + // "psa.measurement-value": s.MeasurementValue, + // "psa.measurement-desc": s.AlgID, + // } + + // if c.Vendor != "" { + // swAttrs["psa.hw-vendor"] = c.Vendor + // } + + // if c.Model != "" { + // swAttrs["psa.hw-model"] = c.Model + // } + + // if s.MeasurementType != "" { + // swAttrs["psa.measurement-type"] = s.MeasurementType + // } + + // if s.Version != "" { + // swAttrs["psa.version"] = s.Version + // } + + // return structpb.NewStruct(swAttrs) +} + +func (o Extractor) TaExtractor(avk comid.AttestVerifKey) (*proto.Endorsement, error) { + // extract instance ID + var psaInstanceAttrs NitroInstanceAttributes + + if err := psaInstanceAttrs.FromEnvironment(avk.Environment); err != nil { + return nil, fmt.Errorf("could not extract PSA instance-id: %w", err) + } + + // extract implementation ID + var nitroClassAttrs NitroClassAttributes + + if err := nitroClassAttrs.FromEnvironment(avk.Environment); err != nil { + return nil, fmt.Errorf("could not extract PSA class attributes: %w", err) + } + + // extract IAK pub + if len(avk.VerifKeys) != 1 { + return nil, errors.New("expecting exactly one IAK public key") + } + + cert := avk.VerifKeys[0].Key + + // TODO(tho) check that format of IAK pub is as expected + + taAttrs, err := makeTaAttrs(psaInstanceAttrs, nitroClassAttrs, cert) + if err != nil { + return nil, fmt.Errorf("failed to create trust anchor attributes: %w", err) + } + + ta := &proto.Endorsement{ + Scheme: proto.AttestationFormat_AWS_NITRO, + Type: proto.EndorsementType_VERIFICATION_KEY, + Attributes: taAttrs, + } + + return ta, nil +} + +func makeTaAttrs(i NitroInstanceAttributes, c NitroClassAttributes, cert string) (*structpb.Struct, error) { + taID := map[string]interface{}{ + "nitro.cert": cert, + } + + if c.Vendor != "" { + taID["nitro.hw-vendor"] = c.Vendor + } + + if c.Model != "" { + taID["nitro.hw-model"] = c.Model + } + + return structpb.NewStruct(taID) +} diff --git a/provisioning/plugins/corim-nitro-decoder/instanceattributes.go b/provisioning/plugins/corim-nitro-decoder/instanceattributes.go new file mode 100644 index 00000000..71e1eb48 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/instanceattributes.go @@ -0,0 +1,16 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "github.com/veraison/corim/comid" +) + +type NitroInstanceAttributes struct { +// InstID eat.UEID nothing in here for now +} + +func (o *NitroInstanceAttributes) FromEnvironment(e comid.Environment) error { + // nothing to do here for now + return nil +} \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/main.go b/provisioning/plugins/corim-nitro-decoder/main.go new file mode 100644 index 00000000..43dde24c --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/main.go @@ -0,0 +1,27 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "github.com/hashicorp/go-plugin" + "github.com/veraison/services/provisioning/decoder" +) + +func main() { + var handshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "VERAISON_PROVISIONING_DECODER_PLUGIN", + MagicCookieValue: "VERAISON", + } + + var pluginMap = map[string]plugin.Plugin{ + "decoder": &decoder.Plugin{ + Impl: &Decoder{}, + }, + } + + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: handshakeConfig, + Plugins: pluginMap, + }) +} diff --git a/provisioning/plugins/corim-nitro-decoder/swcompattributes.go b/provisioning/plugins/corim-nitro-decoder/swcompattributes.go new file mode 100644 index 00000000..933051ee --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/swcompattributes.go @@ -0,0 +1,60 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +import ( + "fmt" + + "github.com/veraison/corim/comid" +) + +type NitroSwCompAttributes struct { + MeasurementType string + Version string + SignerID []byte + AlgID uint64 + MeasurementValue []byte +} + +func (o *NitroSwCompAttributes) FromMeasurement(m comid.Measurement) error { + return fmt.Errorf("Not implemented, not needed?") + // if m.Key == nil { + // return fmt.Errorf("measurement key is not present") + // } + + // // extract psa-swcomp-id from mkey + // if !m.Key.IsSet() { + // return fmt.Errorf("measurement key is not set") + // } + + // id, err := m.Key.GetPSARefValID() + // if err != nil { + // return fmt.Errorf("failed extracting psa-swcomp-id: %w", err) + // } + + // o.SignerID = id.SignerID + + // if id.Label != nil { + // o.MeasurementType = *id.Label + // } + + // if id.Version != nil { + // o.Version = *id.Version + // } + + // // extract digest and alg-id from mval + // d := m.Val.Digests + + // if d == nil { + // return fmt.Errorf("measurement value has no digests") + // } + + // if len(*d) != 1 { + // return fmt.Errorf("expecting exactly one digest") + // } + + // o.AlgID = (*d)[0].HashAlgID + // o.MeasurementValue = (*d)[0].HashValue + + // return nil +} diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.cbor new file mode 100644 index 00000000..5ea8ce91 Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.json b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.json new file mode 100644 index 00000000..9b5e2b55 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComid.json @@ -0,0 +1,40 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "fb6789c3-147d-4e5f-8be0-4452b93c3767", + "version": 0 + }, + "entities": [ + { + "name": "AWS", + "regid": "https://aws.amazon.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "uuid", + "value": "51d1a77a-9908-49e0-92df-e9c872a9b0bd" + }, + "vendor": "AWS", + "model": "Nitro" + } + }, + "verification-keys": [ + { + "key": "MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=" + } + ] + } + ] + } + } + \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.cbor new file mode 100644 index 00000000..5eb9a571 Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.json b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.json new file mode 100644 index 00000000..92fa92e3 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidDualKey.json @@ -0,0 +1,43 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "fb6789c3-147d-4e5f-8be0-4452b93c3767", + "version": 0 + }, + "entities": [ + { + "name": "AWS", + "regid": "https://aws.amazon.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "uuid", + "value": "51d1a77a-9908-49e0-92df-e9c872a9b0bd" + }, + "vendor": "AWS", + "model": "Nitro" + } + }, + "verification-keys": [ + { + "key": "MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=" + }, + { + "key": "BIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=" + } + ] + } + ] + } + } + \ No newline at end of file diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.cbor new file mode 100644 index 00000000..037c39f7 Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.json b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.json new file mode 100644 index 00000000..9574b023 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test-harness/AWSNitroComidNoImplId.json @@ -0,0 +1,36 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "fb6789c3-147d-4e5f-8be0-4452b93c3767", + "version": 0 + }, + "entities": [ + { + "name": "AWS", + "regid": "https://aws.amazon.com", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "vendor": "AWS", + "model": "Nitro" + } + }, + "verification-keys": [ + { + "key": "MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=" + } + ] + } + ] + } + } + diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/corimMini.json b/provisioning/plugins/corim-nitro-decoder/test-harness/corimMini.json new file mode 100644 index 00000000..bc7e70ba --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test-harness/corimMini.json @@ -0,0 +1,3 @@ +{ + "corim-id": "5c57e8f4-46cd-421b-91c9-08cf93e13cfc" +} diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/gen_vectors.sh b/provisioning/plugins/corim-nitro-decoder/test-harness/gen_vectors.sh new file mode 100755 index 00000000..7e5fe0b6 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test-harness/gen_vectors.sh @@ -0,0 +1,20 @@ +# Copyright 2022 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +cocli comid create --template AWSNitroComid.json +cocli corim create -m AWSNitroComid.cbor -t corimMini.json -o unsigned_corim.cbor +echo 'var unsignedCorim = `' +xxd -p unsigned_corim.cbor +echo '`' + +cocli comid create --template AWSNitroComidDualKey.json +cocli corim create -m AWSNitroComidDualKey.cbor -t corimMini.json -o unsigned_corim_dual_key.cbor +echo 'var unsignedCorimDualKey = `' +xxd -p unsigned_corim_dual_key.cbor +echo '`' + +cocli comid create --template AWSNitroComidNoImplId.json +cocli corim create -m AWSNitroComidNoImplId.cbor -t corimMini.json -o unsigned_corim_no_impl_id.cbor +echo 'var unsignedCorimNoImplId = `' +xxd -p unsigned_corim_no_impl_id.cbor +echo '`' diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim.cbor new file mode 100644 index 00000000..f5a4e7cc Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_dual_key.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_dual_key.cbor new file mode 100644 index 00000000..0231b5f2 Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_dual_key.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_no_impl_id.cbor b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_no_impl_id.cbor new file mode 100644 index 00000000..fc42cb85 Binary files /dev/null and b/provisioning/plugins/corim-nitro-decoder/test-harness/unsigned_corim_no_impl_id.cbor differ diff --git a/provisioning/plugins/corim-nitro-decoder/test_vectors.go b/provisioning/plugins/corim-nitro-decoder/test_vectors.go new file mode 100644 index 00000000..826c0cd4 --- /dev/null +++ b/provisioning/plugins/corim-nitro-decoder/test_vectors.go @@ -0,0 +1,124 @@ +// Copyright 2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package main + +// automatically generated from AWSNitroComid.json +var unsignedCorim = ` +a200505c57e8f446cd421b91c908cf93e13cfc018159033cd901faa40065 +656e2d474201a10050fb6789c3147d4e5f8be04452b93c37670281a30063 +41575301d8207668747470733a2f2f6177732e616d617a6f6e2e636f6d02 +8300010204a1028182a100a300d8255051d1a77a990849e092dfe9c872a9 +b0bd016341575302654e6974726f81a1007902c84d49494345544343415a +6167417749424167495241506b78645767626b4b2f684855624d744f546e +2b465977436759494b6f5a497a6a304541774d775354454c4d416b474131 +554542684d4356564d78447a414e42674e5642416f4d426b467459587076 +626a454d4d416f474131554543777744515664544d527377475159445651 +514444424a6864334d75626d6c30636d38745a57356a624746325a584d77 +4868634e4d546b784d4449344d544d794f4441315768634e4e446b784d44 +49344d5451794f444131576a424a4d517377435159445651514745774a56 +557a45504d413047413155454367774751573168656d39754d5177774367 +59445651514c44414e4256314d78477a415a42674e5642414d4d456d4633 +63793575615852796279316c626d4e7359585a6c637a42324d4241474279 +7147534d34394167454742537542424141694132494142507743564f756d +434d487a614844696d747151766b59344d704a7a626f6c4c2f2f5a793259 +6c45533142523554536b736662623438433857426f797437463242773765 +45746161502b6f684732626e557339393064304a58323854635051584345 +505a33424142496554505977456f43575a4568386c35596f51775463552f +394b4e434d45417744775944565230544151482f42415577417745422f7a +416442674e5648513445466751556b43573144646b46522b655777356236 +637033506d616e665335597744675944565230504151482f424151444167 +47474d416f4743437147534d343942414d4441326b414d4759434d51436a +66792b526f636d3958756534596e77576d4e4a5641343466413050355732 +4f70596f77394f59435652614565764c38754f31585972753578744d5057 +72664d434d5143693835735742624a774b4b586453364270745146755a62 +5437336f2f674268317155786c2f6e4e723132554f38596677723677504c +622b364e49774c7a332f593d +` + +// automatically generated from AWSNitroComidDualKey.json +var unsignedCorimDualKey = ` +a200505c57e8f446cd421b91c908cf93e13cfc0181590609d901faa40065 +656e2d474201a10050fb6789c3147d4e5f8be04452b93c37670281a30063 +41575301d8207668747470733a2f2f6177732e616d617a6f6e2e636f6d02 +8300010204a1028182a100a300d8255051d1a77a990849e092dfe9c872a9 +b0bd016341575302654e6974726f82a1007902c84d49494345544343415a +6167417749424167495241506b78645767626b4b2f684855624d744f546e +2b465977436759494b6f5a497a6a304541774d775354454c4d416b474131 +554542684d4356564d78447a414e42674e5642416f4d426b467459587076 +626a454d4d416f474131554543777744515664544d527377475159445651 +514444424a6864334d75626d6c30636d38745a57356a624746325a584d77 +4868634e4d546b784d4449344d544d794f4441315768634e4e446b784d44 +49344d5451794f444131576a424a4d517377435159445651514745774a56 +557a45504d413047413155454367774751573168656d39754d5177774367 +59445651514c44414e4256314d78477a415a42674e5642414d4d456d4633 +63793575615852796279316c626d4e7359585a6c637a42324d4241474279 +7147534d34394167454742537542424141694132494142507743564f756d +434d487a614844696d747151766b59344d704a7a626f6c4c2f2f5a793259 +6c45533142523554536b736662623438433857426f797437463242773765 +45746161502b6f684732626e557339393064304a58323854635051584345 +505a33424142496554505977456f43575a4568386c35596f51775463552f +394b4e434d45417744775944565230544151482f42415577417745422f7a +416442674e5648513445466751556b43573144646b46522b655777356236 +637033506d616e665335597744675944565230504151482f424151444167 +47474d416f4743437147534d343942414d4441326b414d4759434d51436a +66792b526f636d3958756534596e77576d4e4a5641343466413050355732 +4f70596f77394f59435652614565764c38754f31585972753578744d5057 +72664d434d5143693835735742624a774b4b586453364270745146755a62 +5437336f2f674268317155786c2f6e4e723132554f38596677723677504c +622b364e49774c7a332f593da1007902c84249494345544343415a616741 +7749424167495241506b78645767626b4b2f684855624d744f546e2b4659 +77436759494b6f5a497a6a304541774d775354454c4d416b474131554542 +684d4356564d78447a414e42674e5642416f4d426b467459587076626a45 +4d4d416f474131554543777744515664544d527377475159445651514444 +424a6864334d75626d6c30636d38745a57356a624746325a584d77486863 +4e4d546b784d4449344d544d794f4441315768634e4e446b784d4449344d +5451794f444131576a424a4d517377435159445651514745774a56557a45 +504d413047413155454367774751573168656d39754d5177774367594456 +51514c44414e4256314d78477a415a42674e5642414d4d456d4633637935 +75615852796279316c626d4e7359585a6c637a42324d4241474279714753 +4d34394167454742537542424141694132494142507743564f756d434d48 +7a614844696d747151766b59344d704a7a626f6c4c2f2f5a7932596c4553 +3142523554536b736662623438433857426f797437463242773765457461 +61502b6f684732626e557339393064304a58323854635051584345505a33 +424142496554505977456f43575a4568386c35596f51775463552f394b4e +434d45417744775944565230544151482f42415577417745422f7a416442 +674e5648513445466751556b43573144646b46522b655777356236637033 +506d616e665335597744675944565230504151482f42415144416747474d +416f4743437147534d343942414d4441326b414d4759434d51436a66792b +526f636d3958756534596e77576d4e4a56413434664130503557324f7059 +6f77394f59435652614565764c38754f31585972753578744d505772664d +434d5143693835735742624a774b4b586453364270745146755a62543733 +6f2f674268317155786c2f6e4e723132554f38596677723677504c622b36 +4e49774c7a332f593d +` + +var unsignedCorimNoImplId = ` +a200505c57e8f446cd421b91c908cf93e13cfc0181590328d901faa40065 +656e2d474201a10050fb6789c3147d4e5f8be04452b93c37670281a30063 +41575301d8207668747470733a2f2f6177732e616d617a6f6e2e636f6d02 +8300010204a1028182a100a2016341575302654e6974726f81a1007902c8 +4d49494345544343415a6167417749424167495241506b78645767626b4b +2f684855624d744f546e2b465977436759494b6f5a497a6a304541774d77 +5354454c4d416b474131554542684d4356564d78447a414e42674e564241 +6f4d426b467459587076626a454d4d416f47413155454377774451566454 +4d527377475159445651514444424a6864334d75626d6c30636d38745a57 +356a624746325a584d774868634e4d546b784d4449344d544d794f444131 +5768634e4e446b784d4449344d5451794f444131576a424a4d5173774351 +59445651514745774a56557a45504d413047413155454367774751573168 +656d39754d517777436759445651514c44414e4256314d78477a415a4267 +4e5642414d4d456d463363793575615852796279316c626d4e7359585a6c +637a42324d42414742797147534d34394167454742537542424141694132 +494142507743564f756d434d487a614844696d747151766b59344d704a7a +626f6c4c2f2f5a7932596c45533142523554536b73666262343843385742 +6f79743746324277376545746161502b6f684732626e557339393064304a +58323854635051584345505a33424142496554505977456f43575a456838 +6c35596f51775463552f394b4e434d45417744775944565230544151482f +42415577417745422f7a416442674e5648513445466751556b4357314464 +6b46522b655777356236637033506d616e66533559774467594456523050 +4151482f42415144416747474d416f4743437147534d343942414d444132 +6b414d4759434d51436a66792b526f636d3958756534596e77576d4e4a56 +413434664130503557324f70596f77394f59435652614565764c38754f31 +585972753578744d505772664d434d5143693835735742624a774b4b5864 +53364270745146755a625437336f2f674268317155786c2f6e4e72313255 +4f38596677723677504c622b364e49774c7a332f593d +` diff --git a/vts/plugins/Makefile b/vts/plugins/Makefile index a3023a08..7888c5de 100644 --- a/vts/plugins/Makefile +++ b/vts/plugins/Makefile @@ -5,5 +5,6 @@ SUBDIR := common SUBDIR += scheme-tcg-dice SUBDIR += scheme-psa-iot SUBDIR += scheme-tpm-enacttrust +SUBDIR += scheme-aws-nitro include ../../mk/subdir.mk diff --git a/vts/plugins/scheme-aws-nitro/Makefile b/vts/plugins/scheme-aws-nitro/Makefile new file mode 100644 index 00000000..e4e6db05 --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/Makefile @@ -0,0 +1,11 @@ +# Copyright 2021 Contributors to the Veraison project. +# SPDX-License-Identifier: Apache-2.0 + +PLUGIN := ../bin/scheme-aws-nitro +GOPKG := github.com/veraison/services/vts/plugins/scheme-aws-nitro +SRCS := main.go + +include ../../../mk/common.mk +include ../../../mk/plugin.mk +include ../../../mk/lint.mk +include ../../../mk/test.mk \ No newline at end of file diff --git a/vts/plugins/scheme-aws-nitro/main.go b/vts/plugins/scheme-aws-nitro/main.go new file mode 100644 index 00000000..29ec7b61 --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/main.go @@ -0,0 +1,263 @@ +// Copyright 2021-2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "crypto/x509" + "encoding/json" + "encoding/pem" + "fmt" + "net/url" + + "github.com/hashicorp/go-plugin" + nitro_enclave_attestation_document "github.com/veracruz-project/go-nitro-enclave-attestation-document" + "github.com/veraison/services/proto" + "github.com/veraison/services/scheme" +) + +type Endorsements struct { +} + +type Scheme struct{} + +func (s Scheme) GetName() string { + return proto.AttestationFormat_AWS_NITRO.String() +} + +func (s Scheme) GetFormat() proto.AttestationFormat { + return proto.AttestationFormat_AWS_NITRO +} + +func (s Scheme) SynthKeysFromSwComponent(tenantID string, swComp *proto.Endorsement) ([]string, error) { + + var return_array []string // intentionally empty, because we have no SW components in our provisioning corim at this time + return return_array, nil +} + +func (s Scheme) SynthKeysFromTrustAnchor(tenantID string, ta *proto.Endorsement) ([]string, error) { + return []string{nitroTaLookupKey(tenantID)}, nil +} + +func (s Scheme) GetSupportedMediaTypes() []string { + return []string{ + "application/aws-nitro-document", + } +} + +// GetTrustAnchorID returns a string ID used to retrieve a trust anchor +// for this token. The trust anchor may be necessary to validate the +// token and/or extract its claims (if it is encrypted). +func (s Scheme) GetTrustAnchorID(token *proto.AttestationToken) (string, error) { + + return nitroTaLookupKey(token.TenantId), nil +} + +// ExtractClaims parses the attestation token and returns claims +// extracted therefrom. +func (s Scheme) ExtractClaims(token *proto.AttestationToken, trustAnchor string) (*scheme.ExtractedClaims, error) { + ta_unmarshalled := make(map[string]interface{}) + + err := json.Unmarshal([]byte(trustAnchor), &ta_unmarshalled) + if err != nil { + new_err := fmt.Errorf("ExtractVerifiedClaims call to json.Unmarshall failed:%v", err) + return nil, new_err + } + contents, ok := ta_unmarshalled["attributes"].(map[string]interface{}) + if !ok { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims cast of %v to map[string]interface{} failed", ta_unmarshalled["attributes"]) + return nil, new_err + } + cert_pem, ok := contents["nitro.cert"].(string) + if !ok { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims cast of %v to string failed", contents["nitro.cert"]) + return nil, new_err + } + + cert_pem_bytes := []byte(cert_pem) + cert_block, _ := pem.Decode(cert_pem_bytes) + if cert_block == nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims call to pem.Decode failed, but I don't know why") + return nil, new_err + } + + cert_der := cert_block.Bytes + cert, err := x509.ParseCertificate(cert_der) + if err != nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims call to x509.ParseCertificate failed:%v", err) + return nil, new_err + } + + token_data := token.Data + + var document *nitro_enclave_attestation_document.AttestationDocument + + document, err = nitro_enclave_attestation_document.AuthenticateDocument(token_data[1:], *cert) + + if err != nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims call to AuthenticateDocument failed:%v", err) + return nil, new_err + } + + var extracted scheme.ExtractedClaims + + claimsSet, err := claimsToMap(document) + if err != nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ExtractVerifiedClaims call to claimsToMap failed:%v", err) + return nil, new_err + } + extracted.ClaimsSet = claimsSet + + return &extracted, nil +} + +// AppraiseEvidence evaluates the specified EvidenceContext against +// the specified endorsements, and returns an AttestationResult wrapped +// in an AppraisalContext. +func (s Scheme) AppraiseEvidence( + ec *proto.EvidenceContext, endorsementsStrings []string, +) (*proto.AppraisalContext, error) { + appraisalCtx := proto.AppraisalContext{ + Evidence: ec, + Result: &proto.AttestationResult{}, + } + + var endorsements []Endorsements + + for i, e := range endorsementsStrings { + var endorsement Endorsements + + if err := json.Unmarshal([]byte(e), &endorsement); err != nil { + return nil, fmt.Errorf("could not decode endorsement at index %d: %w", i, err) + } + + endorsements = append(endorsements, endorsement) + } + + err := populateAttestationResult(&appraisalCtx, endorsements) + + return &appraisalCtx, err +} + +// ValidateEvidenceIntegrity verifies the structural integrity and validity of the +// token. The exact checks performed are scheme-specific, but they +// would typically involve, at the least, verifying the token's +// signature using the provided trust anchor. If the validation fails, +// an error detailing what went wrong is returned. +// TODO(setrofim): no distinction is currently made between validation +// failing due to an internal error, and it failing due to bad input +// (i.e. signature not matching). +func (s Scheme) ValidateEvidenceIntegrity( + token *proto.AttestationToken, + trustAnchor string, + endorsementsStrings []string, +) error { + ta_unmarshalled := make(map[string]interface{}) + + err := json.Unmarshal([]byte(trustAnchor), &ta_unmarshalled) + if err != nil { + new_err := fmt.Errorf("ValidateEvidenceIntegrity call to json.Unmarshall failed:%v", err) + return new_err + } + contents, ok := ta_unmarshalled["attributes"].(map[string]interface{}) + if !ok { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ValidateEvidenceIntegrity cast of %v to map[string]interface{} failed", ta_unmarshalled["attributes"]) + return new_err + } + + cert_pem, ok := contents["nitro.cert"].(string) + if !ok { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ValidateEvidenceIntegrity cast of %v to string failed", contents["nitro.cert"]) + return new_err + } + + cert_pem_bytes := []byte(cert_pem) + cert_block, _ := pem.Decode(cert_pem_bytes) + if cert_block == nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ValidateEvidenceIntegrity call to pem.Decode failed, but I don't know why") + return new_err + } + + cert_der := cert_block.Bytes + cert, err := x509.ParseCertificate(cert_der) + if err != nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ValidateEvidenceIntegrity call to x509.ParseCertificate failed:%v", err) + return new_err + } + + token_data := token.Data + + _, err = nitro_enclave_attestation_document.AuthenticateDocument(token_data[1:], *cert) + if err != nil { + new_err := fmt.Errorf("scheme-aws-nitro.Scheme.ValidateEvidenceIntegrity call to AuthenticateDocument failed:%v", err) + return new_err + } + return nil +} + +func claimsToMap(doc *nitro_enclave_attestation_document.AttestationDocument) (out map[string]interface{}, err error) { + out = make(map[string]interface{}) + for index, this_pcr := range doc.PCRs { + var key = fmt.Sprintf("PCR%v", index) + out[key] = this_pcr + } + out["user_data"] = doc.UserData + out["nonce"] = doc.Nonce + + return out, nil +} + +func populateAttestationResult(appraisalCtx *proto.AppraisalContext, endorsements []Endorsements) error { + tv := proto.TrustVector{ + InstanceIdentity: int32(proto.ARStatus_NO_CLAIM), + Configuration: int32(proto.ARStatus_NO_CLAIM), + Executables: int32(proto.ARStatus_NO_CLAIM), + FileSystem: int32(proto.ARStatus_NO_CLAIM), + Hardware: int32(proto.ARStatus_NO_CLAIM), + RuntimeOpaque: int32(proto.ARStatus_NO_CLAIM), + StorageOpaque: int32(proto.ARStatus_NO_CLAIM), + SourcedData: int32(proto.ARStatus_NO_CLAIM), + } + + // once the signature on the token is verified, we can claim the HW is + // authentic + tv.Hardware = int32(proto.ARStatus_HW_AFFIRMING) + + appraisalCtx.Result.TrustVector = &tv + + appraisalCtx.Result.Status = proto.TrustTier_AFFIRMING + + appraisalCtx.Result.ProcessedEvidence = appraisalCtx.Evidence.Evidence + + return nil +} + +func nitroTaLookupKey(tenantID string) string { + + u := url.URL{ + Scheme: proto.AttestationFormat_AWS_NITRO.String(), + Host: tenantID, + Path: "/", + } + + return u.String() +} + +func main() { + var handshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "VERAISON_PLUGIN", + MagicCookieValue: "VERAISON", + } + + var pluginMap = map[string]plugin.Plugin{ + "scheme": &scheme.Plugin{ + Impl: &Scheme{}, + }, + } + + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: handshakeConfig, + Plugins: pluginMap, + }) +} diff --git a/vts/plugins/scheme-aws-nitro/main_test.go b/vts/plugins/scheme-aws-nitro/main_test.go new file mode 100644 index 00000000..05a6174e --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/main_test.go @@ -0,0 +1,283 @@ +// Copyright 2021-2022 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "os" + "strings" + "testing" + "time" + + nitro_enclave_attestation_document "github.com/veracruz-project/go-nitro-enclave-attestation-document" + "github.com/veraison/services/proto" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var testTime time.Time = time.Date(2022, 11, 9, 23, 0, 0, 0, time.UTC) + +func generateValidTimeRange(expired bool) (time.Time, time.Time) { + var notBefore time.Time + var notAfter time.Time + if expired { + notBefore = time.Now().Add(-time.Hour * 24) + notAfter = time.Now().Add(-time.Hour * 1) + } else { + notBefore = time.Now() + notAfter = time.Now().Add(time.Hour * 24 * 180) + } + return notBefore, notAfter +} + +func generateCertsAndKeys(endCertExpired bool, caCertExpired bool) (*ecdsa.PrivateKey, []byte, *x509.Certificate, []byte, error) { + caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to generate CA key:%v", err) + } + + caNotBefore, caNotAfter := generateValidTimeRange(caCertExpired) + caTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Acme Co"}, + }, + NotBefore: caNotBefore, + NotAfter: caNotAfter, + + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + IsCA: true, + BasicConstraintsValid: true, + } + + caCertDer, err := x509.CreateCertificate(rand.Reader, &caTemplate, &caTemplate, &caKey.PublicKey, caKey) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("Failed to generate CA Certificate:%v", err) + } + caCert, err := x509.ParseCertificate(caCertDer) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("Failed to convert CA Cert der to certificate:%v", err) + } + + endKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("Failed to generate end key:%v", err) + } + + endNotBefore, endNotAfter := generateValidTimeRange(endCertExpired) + endTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Acme Co"}, + }, + NotBefore: endNotBefore, + NotAfter: endNotAfter, + + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + endCertDer, err := x509.CreateCertificate(rand.Reader, &endTemplate, caCert, &endKey.PublicKey, caKey) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("Failed to generate end certificate:%v", err) + } + return endKey, endCertDer, caCert, caCertDer, nil +} + +const NUM_PCRS = 16 + +func generateRandomSlice(size int32) []byte { + result := make([]byte, size) + rand.Read(result) + return result +} + +func generatePCRs() (map[int32][]byte, error) { + pcrs := make(map[int32][]byte) + for i := int32(0); i < NUM_PCRS; i++ { + pcrs[i] = generateRandomSlice(96) + } + return pcrs, nil +} + +func genTaEndorsements(caCertDer []byte) ([]byte, error) { + taEndValBytes, err := os.ReadFile("test/ta-endorsements.json") + if err != nil { + return nil, fmt.Errorf("os.ReadFile failed:%v\n", err) + } + var pemCertBlock = &pem.Block{ + Type: "CERTIFICATE", + Bytes: caCertDer, + } + caCertPem := string(pem.EncodeToMemory(pemCertBlock)) + caCertJson, err := json.Marshal(caCertPem) + if err != nil { + return nil, fmt.Errorf("json.Marshal failed:%v", err) + } + taEndValString := string(taEndValBytes) + taEndValString = strings.Replace(taEndValString, "\"\"", string(caCertJson), 1) + taEndValBytes = []byte(taEndValString) + return taEndValBytes, nil +} + +func Test_GetTrustAnchorID_ok(t *testing.T) { + privateKey, endCertDer, _, caCertDer, err := generateCertsAndKeys(false, false) + require.NoError(t, err) + + PCRs, err := generatePCRs() + require.NoError(t, err) + userData := generateRandomSlice(32) + nonce := generateRandomSlice(32) + tokenBytes, err := nitro_enclave_attestation_document.GenerateDocument(PCRs, userData, nonce, endCertDer, [][]byte{caCertDer}, privateKey) + require.NoError(t, err) + + token := proto.AttestationToken{ + TenantId: "1", + Format: proto.AttestationFormat_PSA_IOT, + Data: tokenBytes, + } + + expectedTaID := "AWS_NITRO://1/" + + scheme := &Scheme{} + + taID, err := scheme.GetTrustAnchorID(&token) + require.NoError(t, err) + assert.Equal(t, expectedTaID, taID) +} + +func Test_ExtractVerifiedClaims_ok(t *testing.T) { + privateKey, endCertDer, _, caCertDer, err := generateCertsAndKeys(false, false) + require.NoError(t, err) + + PCRs, err := generatePCRs() + require.NoError(t, err) + userData := generateRandomSlice(32) + nonce := generateRandomSlice(32) + tokenBytes, err := nitro_enclave_attestation_document.GenerateDocument(PCRs, userData, nonce, endCertDer, [][]byte{caCertDer}, privateKey) + require.NoError(t, err) + + taEndValBytes, err := genTaEndorsements(caCertDer) + require.NoError(t, err) + + scheme := &Scheme{} + + token := proto.AttestationToken{ + TenantId: "1", + Format: proto.AttestationFormat_AWS_NITRO, + Data: tokenBytes, + } + + extracted, err := scheme.ExtractClaims(&token, string(taEndValBytes)) + + require.NoError(t, err) + assert.Equal(t, PCRs[0][:], extracted.ClaimsSet["PCR0"].([]byte)) + assert.Equal(t, PCRs[1][:], extracted.ClaimsSet["PCR1"].([]byte)) + assert.Equal(t, PCRs[2][:], extracted.ClaimsSet["PCR2"].([]byte)) + assert.Equal(t, PCRs[3][:], extracted.ClaimsSet["PCR3"].([]byte)) + assert.Equal(t, PCRs[4][:], extracted.ClaimsSet["PCR4"].([]byte)) + assert.Equal(t, PCRs[5][:], extracted.ClaimsSet["PCR5"].([]byte)) + assert.Equal(t, PCRs[6][:], extracted.ClaimsSet["PCR6"].([]byte)) + assert.Equal(t, PCRs[7][:], extracted.ClaimsSet["PCR7"].([]byte)) + assert.Equal(t, PCRs[8][:], extracted.ClaimsSet["PCR8"].([]byte)) + assert.Equal(t, PCRs[9][:], extracted.ClaimsSet["PCR9"].([]byte)) + assert.Equal(t, PCRs[10][:], extracted.ClaimsSet["PCR10"].([]byte)) + assert.Equal(t, PCRs[11][:], extracted.ClaimsSet["PCR11"].([]byte)) + assert.Equal(t, PCRs[12][:], extracted.ClaimsSet["PCR12"].([]byte)) + assert.Equal(t, PCRs[13][:], extracted.ClaimsSet["PCR13"].([]byte)) + assert.Equal(t, PCRs[14][:], extracted.ClaimsSet["PCR14"].([]byte)) + assert.Equal(t, PCRs[15][:], extracted.ClaimsSet["PCR15"].([]byte)) + + receivedNonce := extracted.ClaimsSet["nonce"].([]byte) + assert.Equal(t, nonce[:], receivedNonce[:]) + + receivedUserData := extracted.ClaimsSet["user_data"].([]byte) + assert.Equal(t, userData[:], receivedUserData[:]) +} + +func Test_ExtractVerifiedClaims_bad_signature(t *testing.T) { + privateKey, endCertDer, _, caCertDer, err := generateCertsAndKeys(false, false) + require.NoError(t, err) + + PCRs, err := generatePCRs() + require.NoError(t, err) + userData := generateRandomSlice(32) + nonce := generateRandomSlice(32) + tokenBytes, err := nitro_enclave_attestation_document.GenerateDocument(PCRs, userData, nonce, endCertDer, [][]byte{caCertDer}, privateKey) + require.NoError(t, err) + + // modify the signature to make it fail + tokenBytes[len(tokenBytes)-1] ^= tokenBytes[len(tokenBytes)-1] + + taEndValBytes, err := genTaEndorsements(caCertDer) + require.NoError(t, err) + + scheme := &Scheme{} + + token := proto.AttestationToken{ + TenantId: "1", + Format: proto.AttestationFormat_AWS_NITRO, + Data: tokenBytes, + } + + _, err = scheme.ExtractClaims(&token, string(taEndValBytes)) + + assert.EqualError(t, err, `scheme-aws-nitro.Scheme.ExtractVerifiedClaims call to AuthenticateDocument failed:AuthenticateDocument::Verify failed:verification error`) +} + +func Test_ValidateEvidenceIntegrity_ok(t *testing.T) { + privateKey, endCertDer, _, caCertDer, err := generateCertsAndKeys(false, false) + require.NoError(t, err) + + PCRs, err := generatePCRs() + require.NoError(t, err) + userData := generateRandomSlice(32) + nonce := generateRandomSlice(32) + tokenBytes, err := nitro_enclave_attestation_document.GenerateDocument(PCRs, userData, nonce, endCertDer, [][]byte{caCertDer}, privateKey) + require.NoError(t, err) + + taEndValBytes, err := genTaEndorsements(caCertDer) + require.NoError(t, err) + + scheme := &Scheme{} + + token := proto.AttestationToken{ + TenantId: "1", + Format: proto.AttestationFormat_AWS_NITRO, + Data: tokenBytes, + } + + err = scheme.ValidateEvidenceIntegrity(&token, string(taEndValBytes), nil) + + assert.NoError(t, err) +} + +func Test_AppraiseEvidence_ok(t *testing.T) { + extractedBytes, err := os.ReadFile("test/extracted.json") + require.NoError(t, err) + + var ec proto.EvidenceContext + err = json.Unmarshal(extractedBytes, &ec) + require.NoError(t, err) + + endorsementsBytes, err := os.ReadFile("test/endorsements.json") + require.NoError(t, err) + + scheme := &Scheme{} + + attestation, err := scheme.AppraiseEvidence(&ec, []string{string(endorsementsBytes)}) + require.NoError(t, err) + + assert.Equal(t, proto.TrustTier_AFFIRMING, attestation.Result.Status) +} diff --git a/vts/plugins/scheme-aws-nitro/test/endorsements.json b/vts/plugins/scheme-aws-nitro/test/endorsements.json new file mode 100644 index 00000000..0b66aae7 --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/test/endorsements.json @@ -0,0 +1,8 @@ +{ + "scheme": "AWS_NITRO", + "type": "VERIFICATION_KEY", + "attributes": { + "nitro.cert": "MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/Y=" + } +} + diff --git a/vts/plugins/scheme-aws-nitro/test/extracted.json b/vts/plugins/scheme-aws-nitro/test/extracted.json new file mode 100644 index 00000000..8fc17ad1 --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/test/extracted.json @@ -0,0 +1,22 @@ +{ + "evidence": { + "PCR0": [34, 249, 225, 201, 73, 32, 141, 165, 94, 176, 27, 155, 159, 200, 143, 135, 69, 79, 119, 186, 19, 63, 13, 130, 50, 11, 80, 150, 33, 201, 36, 130, 21, 42, 153, 208, 161, 35, 53, 185, 113, 120, 192, 45, 111, 151, 125, 1], + "PCR1":[188, 223, 5, 254, 252, 202, 168, 229, 91, 242, 200, 214, 222, 233, 231, 155, 191, 243, 30, 52, 191, 40, 169, 154, 161, 158, 107, 41, 195, 126, 232, 11, 33, 74, 65, 75, 118, 7, 35, 110, 223, 38, 252, 183, 134, 84, 230, 63], + "PCR10":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR11":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR12":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR13":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR14":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR15":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR2":[0, 148, 62, 168, 89, 20, 15, 237, 116, 225, 2, 95, 228, 26, 237, 179, 135, 128, 234, 229, 101, 107, 63, 158, 249, 180, 176, 230, 17, 19, 80, 49, 85, 68, 219, 62, 252, 218, 5, 114, 81, 8, 247, 43, 42, 177, 65, 247], + "PCR3":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR4":[69, 84, 4, 35, 57, 230, 161, 221, 250, 200, 157, 183, 218, 88, 35, 29, 86, 25, 7, 55, 41, 52, 67, 51, 175, 240, 85, 66, 154, 190, 236, 107, 0, 111, 129, 177, 157, 17, 118, 0, 27, 130, 145, 248, 133, 40, 49, 6], + "PCR5":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR6":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR7":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR8":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "PCR9":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "nonce":[198, 120, 200, 97, 53, 222, 83, 157, 24, 58, 207, 245, 136, 134, 217, 141, 251, 152, 35, 4, 26, 249, 249, 52, 191, 144, 154, 192, 248, 217, 98, 69], + "user_data":[124, 55, 16, 128, 121, 179, 232, 163, 109, 138, 121, 112, 222, 29, 109, 79, 241, 70, 30, 14, 53, 217, 85, 124, 77, 120, 157, 245, 224, 87, 102, 32] + } +} diff --git a/vts/plugins/scheme-aws-nitro/test/ta-endorsements.json b/vts/plugins/scheme-aws-nitro/test/ta-endorsements.json new file mode 100644 index 00000000..84d09f8d --- /dev/null +++ b/vts/plugins/scheme-aws-nitro/test/ta-endorsements.json @@ -0,0 +1,7 @@ +{ + "scheme":"AWS_NITRO", + "type":"VERIFICATION_KEY", + "attributes":{ + "nitro.cert": "" + } +} \ No newline at end of file diff --git a/vts/trustedservices/trustedservices_grpc.go b/vts/trustedservices/trustedservices_grpc.go index 62d40dca..4b460395 100644 --- a/vts/trustedservices/trustedservices_grpc.go +++ b/vts/trustedservices/trustedservices_grpc.go @@ -313,9 +313,13 @@ func (o *GRPC) GetAttestation( o.logger.Debugw("constructed evidence context", "software-id", ec.SoftwareId, "trust-anchor-id", ec.TrustAnchorId) - endorsements, err := o.EnStore.Get(ec.SoftwareId) - if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) { - return nil, err + var endorsements []string + if ec.SoftwareId != "" { + endorsements, err = o.EnStore.Get(ec.SoftwareId) + if err != nil && !errors.Is(err, kvstore.ErrKeyNotFound) { + + return nil, err + } } if len(endorsements) > 0 {