From 3ed001fa8a02eacba59dbc1c9b90c4d2c3fad42d Mon Sep 17 00:00:00 2001 From: Moritz Sanft <58110325+msanft@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:08:00 +0200 Subject: [PATCH] attestation: use `go-sev-guest` library (#2269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip: switch to attestation * add extra comments Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * MAA checks Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use provided functions to parse report / cert chain Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * replace `CommitedTCB` check with `LaunchTCB` check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove debug check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove `LaunchTCB` == `CommitedTCB` check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * custom IdKeyDigests check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * basic test of report parsing from instance info Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * retrieve VCEK from AMD KDS Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove VCEK from `azureInstanceInfo` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use `go-sev-guest` TCB version type Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix validation parsing test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix error message * fix comment Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove certificate chain from `instanceInfo` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add test for idkeydigest check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * update buildfiles Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * wip: update tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * update buildfiles Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * [remove] debug prints Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * wip: fix tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * wip: fix tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix tests, do some clean-up Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add test case for fetching error Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> * correct `hack` dependency Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix id key check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * [remove] comment out wip unit tests Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add missing newline Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * switch to released version of `go-sev-guest` Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add constructor test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add VMPL check Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * add test assertions Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * update buildfiles Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * switch to pseudoversion Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use fork with windows fix Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix linter checks Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use data from THIM Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * update embeds Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * verify against ARK in config Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * invalid ASK Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: 3u13r * Update internal/attestation/azure/snp/validator.go Co-authored-by: 3u13r * nits Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * remove unnecessary checks Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * refactoring Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> * use upstream library with pseudoversion Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> * Update internal/attestation/azure/snp/validator.go Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> * simplify control flow Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix return error Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix VCEK test Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * tidy Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * revert unintentional changes Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * use new upstream release Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix removed AuthorKeyEn field Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> * fix verification report printing Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> --------- Signed-off-by: Moritz Sanft <58110325+msanft@users.noreply.github.com> Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> Co-authored-by: Thomas Tendyck <51411342+thomasten@users.noreply.github.com> Co-authored-by: 3u13r Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> --- bazel/toolchains/go_module_deps.bzl | 24 +- cli/internal/cmd/verify.go | 10 +- go.mod | 12 +- go.sum | 23 +- hack/go.mod | 12 +- hack/go.sum | 23 +- internal/attestation/azure/snp/BUILD.bazel | 15 +- internal/attestation/azure/snp/errors.go | 76 -- internal/attestation/azure/snp/issuer.go | 2 +- internal/attestation/azure/snp/issuer_test.go | 2 +- .../azure/snp/testdata/BUILD.bazel | 15 + .../azure/snp/testdata/attestation.bin | Bin 0 -> 1204 bytes .../azure/snp/testdata/certchain.pem | 74 ++ .../azure/snp/testdata/runtimedata.bin | 1 + .../azure/snp/testdata/testdata.go | 35 + .../attestation/azure/snp/testdata/vcek.cert | Bin 0 -> 1360 bytes .../attestation/azure/snp/testdata/vcek.pem | 31 + internal/attestation/azure/snp/validator.go | 571 ++++----- .../attestation/azure/snp/validator_test.go | 1039 +++++++++++++---- operators/constellation-node-operator/go.mod | 10 +- operators/constellation-node-operator/go.sum | 20 +- 21 files changed, 1371 insertions(+), 624 deletions(-) delete mode 100644 internal/attestation/azure/snp/errors.go create mode 100644 internal/attestation/azure/snp/testdata/BUILD.bazel create mode 100644 internal/attestation/azure/snp/testdata/attestation.bin create mode 100644 internal/attestation/azure/snp/testdata/certchain.pem create mode 100644 internal/attestation/azure/snp/testdata/runtimedata.bin create mode 100644 internal/attestation/azure/snp/testdata/testdata.go create mode 100644 internal/attestation/azure/snp/testdata/vcek.cert create mode 100644 internal/attestation/azure/snp/testdata/vcek.pem diff --git a/bazel/toolchains/go_module_deps.bzl b/bazel/toolchains/go_module_deps.bzl index b38461eef..e2b48cb8b 100644 --- a/bazel/toolchains/go_module_deps.bzl +++ b/bazel/toolchains/go_module_deps.bzl @@ -2456,8 +2456,8 @@ def go_dependencies(): build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "github.com/google/go-sev-guest", - sum = "h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0=", - version = "v0.6.1", + sum = "h1:IIZIqdcMJXgTm1nMvId442OUpYebbWDWa9bi9/lUUwc=", + version = "v0.8.0", ) go_repository( name = "com_github_google_go_tpm", @@ -2595,8 +2595,8 @@ def go_dependencies(): build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "github.com/google/uuid", - sum = "h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=", - version = "v1.3.0", + sum = "h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=", + version = "v1.3.1", ) go_repository( name = "com_github_google_wire", @@ -7324,8 +7324,8 @@ def go_dependencies(): build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "golang.org/x/crypto", - sum = "h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=", - version = "v0.12.0", + sum = "h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=", + version = "v0.13.0", ) go_repository( name = "org_golang_x_exp", @@ -7397,24 +7397,24 @@ def go_dependencies(): build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "golang.org/x/sys", - sum = "h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=", - version = "v0.11.0", + sum = "h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=", + version = "v0.12.0", ) go_repository( name = "org_golang_x_term", build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "golang.org/x/term", - sum = "h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=", - version = "v0.11.0", + sum = "h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=", + version = "v0.12.0", ) go_repository( name = "org_golang_x_text", build_file_generation = "on", build_file_proto_mode = "disable_global", importpath = "golang.org/x/text", - sum = "h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=", - version = "v0.12.0", + sum = "h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=", + version = "v0.13.0", ) go_repository( name = "org_golang_x_time", diff --git a/cli/internal/cmd/verify.go b/cli/internal/cmd/verify.go index 8d4151d34..fc219890a 100644 --- a/cli/internal/cmd/verify.go +++ b/cli/internal/cmd/verify.go @@ -428,6 +428,11 @@ func (f *attestationDocFormatterImpl) parseSNPReport(b *strings.Builder, reportB return fmt.Errorf("parsing signature: %w", err) } + signerInfo, err := abi.ParseSignerInfo(report.SignerInfo) + if err != nil { + return fmt.Errorf("parsing signer info: %w", err) + } + writeTCB := func(tcbVersion uint64) { tcb := kds.DecomposeTCBVersion(kds.TCBVersion(tcbVersion)) writeIndentfln(b, 3, "Secure Processor bootloader SVN: %d", tcb.BlSpl) @@ -459,7 +464,10 @@ func (f *attestationDocFormatterImpl) parseSNPReport(b *strings.Builder, reportB writeIndentfln(b, 2, "Platform Info:") writeIndentfln(b, 3, "Symmetric Multithreading enabled (SMT): %t", platformInfo.SMTEnabled) writeIndentfln(b, 3, "Transparent secure memory encryption (TSME): %t", platformInfo.TSMEEnabled) - writeIndentfln(b, 2, "Author Key ID: %x", report.AuthorKeyEn) + writeIndentfln(b, 2, "Signer Info:") + writeIndentfln(b, 3, "Author Key Enabled: %t", signerInfo.AuthorKeyEn) + writeIndentfln(b, 3, "Chip ID Masking: %t", signerInfo.MaskChipKey) + writeIndentfln(b, 3, "Signing Type: %s", signerInfo.SigningKey) writeIndentfln(b, 2, "Report Data: %x", report.ReportData) writeIndentfln(b, 2, "Measurement: %x", report.Measurement) writeIndentfln(b, 2, "Host Data: %x", report.HostData) diff --git a/go.mod b/go.mod index c7a9983fc..c350c9579 100644 --- a/go.mod +++ b/go.mod @@ -77,10 +77,10 @@ require ( github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/validator/v10 v10.14.1 github.com/golang-jwt/jwt/v5 v5.0.0 - github.com/google/go-sev-guest v0.6.1 + github.com/google/go-sev-guest v0.8.0 github.com/google/go-tpm v0.9.0 github.com/google/go-tpm-tools v0.4.0 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/googleapis/gax-go/v2 v2.12.0 github.com/gophercloud/gophercloud v1.5.0 github.com/gophercloud/utils v0.0.0-20230523080330-de873b9cf00d @@ -109,9 +109,9 @@ require ( github.com/theupdateframework/go-tuf v0.5.2 go.uber.org/goleak v1.2.1 go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.12.0 + golang.org/x/crypto v0.13.0 golang.org/x/mod v0.12.0 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 golang.org/x/tools v0.10.0 google.golang.org/api v0.130.0 google.golang.org/grpc v1.56.2 @@ -321,8 +321,8 @@ require ( golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 9dfb05746..96c32b805 100644 --- a/go.sum +++ b/go.sum @@ -535,8 +535,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= -github.com/google/go-sev-guest v0.6.1 h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0= -github.com/google/go-sev-guest v0.6.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= +github.com/google/go-sev-guest v0.8.0 h1:IIZIqdcMJXgTm1nMvId442OUpYebbWDWa9bi9/lUUwc= +github.com/google/go-sev-guest v0.8.0/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/go-tpm-tools v0.4.0 h1:bYRZAUvQEmn11WTKCkTLRCCv4aTlOBgBBeqCK0ABT2A= github.com/google/go-tpm-tools v0.4.0/go.mod h1:G7PFUk8KKQzdYYGv/cpV9LB9sPT7czAAomnceugzNKQ= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= @@ -573,8 +573,9 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -1112,8 +1113,8 @@ golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1313,8 +1314,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1322,8 +1323,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1337,8 +1338,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/hack/go.mod b/hack/go.mod index 6c022666e..0884227d3 100644 --- a/hack/go.mod +++ b/hack/go.mod @@ -168,7 +168,7 @@ require ( github.com/google/go-attestation v0.5.0 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-containerregistry v0.15.2 // indirect - github.com/google/go-sev-guest v0.6.1 // indirect + github.com/google/go-sev-guest v0.8.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/go-tpm-tools v0.4.0 // indirect github.com/google/go-tspi v0.3.0 // indirect @@ -176,7 +176,7 @@ require ( github.com/google/logger v1.1.1 // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gophercloud/gophercloud v1.5.0 // indirect @@ -280,13 +280,13 @@ require ( go.starlark.net v0.0.0-20220223235035-243c74974e97 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.10.0 // indirect google.golang.org/api v0.130.0 // indirect diff --git a/hack/go.sum b/hack/go.sum index 4ac1bb8e2..d1d43081e 100644 --- a/hack/go.sum +++ b/hack/go.sum @@ -496,8 +496,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= -github.com/google/go-sev-guest v0.6.1 h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0= -github.com/google/go-sev-guest v0.6.1/go.mod h1:UEi9uwoPbLdKGl1QHaq1G8pfCbQ4QP0swWX4J0k6r+Q= +github.com/google/go-sev-guest v0.8.0 h1:IIZIqdcMJXgTm1nMvId442OUpYebbWDWa9bi9/lUUwc= +github.com/google/go-sev-guest v0.8.0/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/go-tpm-tools v0.4.0 h1:bYRZAUvQEmn11WTKCkTLRCCv4aTlOBgBBeqCK0ABT2A= @@ -533,8 +533,9 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -1068,8 +1069,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1269,16 +1270,16 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1293,8 +1294,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/attestation/azure/snp/BUILD.bazel b/internal/attestation/azure/snp/BUILD.bazel index fd27a899c..42b54de5f 100644 --- a/internal/attestation/azure/snp/BUILD.bazel +++ b/internal/attestation/azure/snp/BUILD.bazel @@ -4,7 +4,6 @@ load("//bazel/go:go_test.bzl", "go_test") go_library( name = "snp", srcs = [ - "errors.go", "imds.go", "issuer.go", "maa.go", @@ -20,8 +19,13 @@ go_library( "//internal/attestation/vtpm", "//internal/cloud/azure", "//internal/config", - "//internal/crypto", "@com_github_edgelesssys_go_azguestattestation//maa", + "@com_github_google_go_sev_guest//abi", + "@com_github_google_go_sev_guest//kds", + "@com_github_google_go_sev_guest//proto/sevsnp", + "@com_github_google_go_sev_guest//validate", + "@com_github_google_go_sev_guest//verify", + "@com_github_google_go_sev_guest//verify/trust", "@com_github_google_go_tpm//legacy/tpm2", "@com_github_google_go_tpm_tools//client", "@com_github_google_go_tpm_tools//proto/attest", @@ -42,12 +46,19 @@ go_test( "//conditions:default": ["disable_tpm_simulator"], }), deps = [ + "//internal/attestation", + "//internal/attestation/azure/snp/testdata", "//internal/attestation/idkeydigest", "//internal/attestation/simulator", "//internal/attestation/vtpm", "//internal/config", "//internal/logger", "@com_github_edgelesssys_go_azguestattestation//maa", + "@com_github_google_go_sev_guest//abi", + "@com_github_google_go_sev_guest//kds", + "@com_github_google_go_sev_guest//proto/sevsnp", + "@com_github_google_go_sev_guest//validate", + "@com_github_google_go_sev_guest//verify", "@com_github_google_go_tpm//legacy/tpm2", "@com_github_google_go_tpm_tools//client", "@com_github_google_go_tpm_tools//proto/attest", diff --git a/internal/attestation/azure/snp/errors.go b/internal/attestation/azure/snp/errors.go deleted file mode 100644 index 1b879eb08..000000000 --- a/internal/attestation/azure/snp/errors.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package snp - -import ( - "errors" - "fmt" -) - -type signatureError struct { - innerError error -} - -func (e *signatureError) Unwrap() error { - return e.innerError -} - -func (e *signatureError) Error() string { - return fmt.Sprintf("signature validation failed: %v", e.innerError) -} - -type askError struct { - innerError error -} - -func (e *askError) Unwrap() error { - return e.innerError -} - -func (e *askError) Error() string { - return fmt.Sprintf("validating ASK: %v", e.innerError) -} - -type vcekError struct { - innerError error -} - -func (e *vcekError) Unwrap() error { - return e.innerError -} - -func (e *vcekError) Error() string { - return fmt.Sprintf("validating VCEK: %v", e.innerError) -} - -type idKeyError struct { - encounteredValue []byte - expectedValues [][]byte -} - -func (e *idKeyError) Unwrap() error { - return nil -} - -func (e *idKeyError) Error() string { - return fmt.Sprintf("accepted idkeydigest list %x doesn't contain reported idkeydigest %x", e.expectedValues, e.encounteredValue) -} - -type versionError struct { - expectedType string - excpectedVersion tcbVersion -} - -func (e *versionError) Unwrap() error { - return nil -} - -func (e *versionError) Error() string { - return fmt.Sprintf("invalid %s version: %x", e.expectedType, e.excpectedVersion) -} - -var errDebugEnabled = errors.New("SNP report indicates debugging, expected no debugging") diff --git a/internal/attestation/azure/snp/issuer.go b/internal/attestation/azure/snp/issuer.go index 7ba7f8d1e..d527044aa 100644 --- a/internal/attestation/azure/snp/issuer.go +++ b/internal/attestation/azure/snp/issuer.go @@ -66,7 +66,7 @@ func (i *Issuer) getInstanceInfo(ctx context.Context, tpm io.ReadWriteCloser, us } instanceInfo := azureInstanceInfo{ - Vcek: params.VcekCert, + VCEK: params.VcekCert, CertChain: params.VcekChain, AttestationReport: params.SNPReport, RuntimeData: params.RuntimeData, diff --git a/internal/attestation/azure/snp/issuer_test.go b/internal/attestation/azure/snp/issuer_test.go index 06aa78b6b..4f61c9fab 100644 --- a/internal/attestation/azure/snp/issuer_test.go +++ b/internal/attestation/azure/snp/issuer_test.go @@ -103,7 +103,7 @@ func TestGetSNPAttestation(t *testing.T) { err = json.Unmarshal(attestationJSON, &instanceInfo) require.NoError(err) - assert.Equal(params.VcekCert, instanceInfo.Vcek) + assert.Equal(params.VcekCert, instanceInfo.VCEK) assert.Equal(params.VcekChain, instanceInfo.CertChain) assert.Equal(params.SNPReport, instanceInfo.AttestationReport) assert.Equal(params.RuntimeData, instanceInfo.RuntimeData) diff --git a/internal/attestation/azure/snp/testdata/BUILD.bazel b/internal/attestation/azure/snp/testdata/BUILD.bazel new file mode 100644 index 000000000..9b09a6fdb --- /dev/null +++ b/internal/attestation/azure/snp/testdata/BUILD.bazel @@ -0,0 +1,15 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "testdata", + srcs = ["testdata.go"], + embedsrcs = [ + "attestation.bin", + "vcek.cert", + "certchain.pem", + "runtimedata.bin", + "vcek.pem", + ], + importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp/testdata", + visibility = ["//:__subpackages__"], +) diff --git a/internal/attestation/azure/snp/testdata/attestation.bin b/internal/attestation/azure/snp/testdata/attestation.bin new file mode 100644 index 0000000000000000000000000000000000000000..efe048b0dd5c6f0fe8bd7ba9448a05195a8e19b8 GIT binary patch literal 1204 zcmZQ#U|?VZVtEE;Aj!bM2qqB(NDdu<)Ih}9V$s#}oZ*=IUSG$$r#0j2qTQ+gqkmdd zahgtdTI=|%?bP|p-RNea^TWzN-fP#GS9R(5%Q+3PEEyYDp1EPqs}l7q$mt5}E#Gj} zR{fsTfH04Or=Jyae@i%`>qqB@Khk{g|LLzu7k=ISpR87})X*)Mv%Tfi7* z$UW8K)_(#37LK^=ndh?VJ=6J9`FD4nN}H4OSM%ZO-s!JTTDBHytl2HRqlEXfh}mVo zwx>VV@!WrH#U~NFCHKu5@toteWim<&ci#CF4Ktt7n2`a5VSHTn4L0#T+wX|3{@>xj z^t@#AtlKM|{jdA;AxQ&7$*l(NLUIdNViV*?9g14AQ2QzMfoab9BsB(6af%w}3UPSAiK z;y4bFy$#BM?qvrC@i|*2MmARMMivGo<|GD|mal)f;`5j{e_U~KbJenCD%Uvm z<*$nPzq$Wj%Q8Fa+@;>4TK^0ti@6u=PA-i%s8(V=(Cx38H*4zj!T@*M*4halMc3Uj zZu|AxfAXU4%PUj9v8(UDW*ga~UbN>=&v&L1!Hb(1#SEGlL7~N|&Bn;WIH!VN*)12(od(lrn?WGNA}DL9`>QV!;$*#S~)06k^8|Vg?DZq1ea) z5{fnOML3v+#bKVys`pIiPvzg;bt-L6&R@-kt9z%vK55xnsIg|Z@QxDR&mv}*{o0=X zSjTh!wH2R4?3Ua&Ys7Po*OtjBE!=tMQ#7@bJaZE;Ff&3jm`g%y8Z~ zwCgdWe4Po8$@Cn>rM7ab+c<7rTEIQam0xa@{#k?aHve@KXMKP6VU^iB!OhRD|B1;Y+k8szS;J@}+Z5~?c|AUyFJM(43G+a6z6YWQ_aCBJ2BzIAr~Ch3VYvfgBzn9UTT_w4IFodpSDyW^{B@?wr*= CommittedTCB. + PermitProvisionalFirmware: true, + // Check if the IDKey hash in the report is in the list of accepted hashes. + TrustedIDKeyHashes: v.config.FirmwareSignerConfig.AcceptedKeyDigests, + // The IDKey hash should not be checked if the enforcement policy is set to MAAFallback or WarnOnly to prevent + // an error from being returned because of the TrustedIDKeyHashes validation. In this case, we should perform a + // custom check of the MAA-specific values later. Right now, this is a double check, since a custom MAA check + // is performed either way. + RequireIDBlock: v.config.FirmwareSignerConfig.EnforcementPolicy == idkeydigest.Equal, + }); err != nil { + return nil, fmt.Errorf("validating SNP attestation: %w", err) + } + // Custom check of the IDKeyDigests, taking care of the WarnOnly / MAAFallback cases, + // but also double-checking the IDKeyDigests if the enforcement policy is set to Equal. + if err := v.checkIDKeyDigest(ctx, att, instanceInfo.MAAToken, extraData); err != nil { + return nil, fmt.Errorf("checking IDKey digests: %w", err) + } + + // Decode the public area of the attestation key and validate its trustworthiness. pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub) if err != nil { return nil, err } - - if err = v.hclValidator.validateAk(instanceInfo.RuntimeData, report.ReportData[:], pubArea.RSAParameters); err != nil { + if err = v.hclValidator.validateAk(instanceInfo.RuntimeData, att.Report.ReportData, pubArea.RSAParameters); err != nil { return nil, fmt.Errorf("validating HCLAkPub: %w", err) } return pubArea.Key() } -// validateVCEK takes the PEM-encoded X509 certificate VCEK, ASK and ARK and verifies the integrity of the chain. -// ARK (hardcoded) validates ASK (cloud metadata API) validates VCEK (cloud metadata API). -func (v *Validator) validateVCEK(vcekRaw []byte, certChain []byte) (*x509.Certificate, error) { - vcek, err := internalCrypto.PemToX509Cert(vcekRaw) +// checkIDKeyDigest validates the IDKeyDigest in the given attestation report against the accepted IDKeyDigests in the +// validator's config. If an IDKeyDigest is present in the report that is not in the accepted IDKeyDigests, the validation proceeds +// according to the enforcement policy. If the enforcement policy is set to MAAFallback, the maaToken is validated against the MAA. +// If the enforcement policy is set to WarnOnly, a warning is logged. If the enforcement policy is set to neither WarnOnly or MAAFallback, an +// error is returned. +func (v *Validator) checkIDKeyDigest(ctx context.Context, report *spb.Attestation, maaToken string, extraData []byte) error { + for _, digest := range v.config.FirmwareSignerConfig.AcceptedKeyDigests { + if bytes.Equal(digest, report.Report.IdKeyDigest) { + return nil + } + } + + // IDKeyDigest that was not expected is present, check the enforcement policy and verify against + // the MAA if necessary. + switch v.config.FirmwareSignerConfig.EnforcementPolicy { + case idkeydigest.MAAFallback: + v.log.Infof( + "Configured idkeydigests %x don't contain reported idkeydigest %x, falling back to MAA validation", + v.config.FirmwareSignerConfig.AcceptedKeyDigests, + report.Report.IdKeyDigest, + ) + return v.maa.validateToken(ctx, v.config.FirmwareSignerConfig.MAAURL, maaToken, extraData) + case idkeydigest.WarnOnly: + v.log.Warnf( + "Configured idkeydigests %x don't contain reported idkeydigest %x", + v.config.FirmwareSignerConfig.AcceptedKeyDigests, + report.Report.IdKeyDigest, + ) + default: + return fmt.Errorf( + "configured idkeydigests %x don't contain reported idkeydigest %x", + v.config.FirmwareSignerConfig.AcceptedKeyDigests, + report.Report.IdKeyDigest, + ) + } + + // No IDKeyDigest that was not expected is present. + return nil +} + +// azureInstanceInfo contains the necessary information to establish trust in +// an Azure CVM. +type azureInstanceInfo struct { + // VCEK is the PEM-encoded VCEK certificate for the attestation report. + VCEK []byte + // CertChain is the PEM-encoded certificate chain for the attestation report. + CertChain []byte + // AttestationReport is the attestation report from the vTPM (NVRAM) of the CVM. + AttestationReport []byte + // RuntimeData is the Azure runtime data from the vTPM (NVRAM) of the CVM. + RuntimeData []byte + // MAAToken is the token of the MAA for the attestation report, used as a fallback + // if the IDKeyDigest cannot be verified. + MAAToken string +} + +// attestationWithCerts returns a formatted version of the attestation report and its certificates from the instanceInfo. +// if the VCEK certificate or the certificate chain is not present, the given getter is used to retrieve them +// from the AMD KDS. +func (a *azureInstanceInfo) attestationWithCerts(logger attestation.Logger, getter trust.HTTPSGetter) (*spb.Attestation, error) { + report, err := abi.ReportToProto(a.AttestationReport) if err != nil { - return nil, fmt.Errorf("loading vcek: %w", err) + return nil, fmt.Errorf("converting report to proto: %w", err) } - // certChain includes two PEM encoded certs. The ASK and the ARK, in that order. - ask, err := internalCrypto.PemToX509Cert(certChain) + // Product info as reported through CPUID[EAX=1] + sevProduct := abi.DefaultSevProduct() + productName := kds.ProductString(sevProduct) + + att := &spb.Attestation{ + Report: report, + CertificateChain: &spb.CertificateChain{}, + Product: sevProduct, + } + + // If the VCEK certificate is present, parse it and format it. + vcek, err := a.parseVCEK() if err != nil { - return nil, fmt.Errorf("loading askPEM: %w", err) + logger.Warnf("Error parsing VCEK: %v", err) + } + if vcek != nil { + att.CertificateChain.VcekCert = vcek.Raw + } else { + // Otherwise, retrieve it from AMD KDS. + logger.Infof("VCEK certificate not present, falling back to retrieving it from AMD KDS") + vcekURL := kds.VCEKCertURL(productName, report.GetChipId(), kds.TCBVersion(report.GetReportedTcb())) + vcek, err := getter.Get(vcekURL) + if err != nil { + return nil, fmt.Errorf("retrieving VCEK certificate from AMD KDS: %w", err) + } + att.CertificateChain.VcekCert = vcek } - if err = ask.CheckSignatureFrom((*x509.Certificate)(&v.config.AMDRootKey)); err != nil { - return nil, &askError{err} + // If the certificate chain is present, parse it and format it. + ask, ark, err := a.parseCertChain() + if err != nil { + logger.Warnf("Error parsing certificate chain: %v", err) + } + if ask != nil { + att.CertificateChain.AskCert = ask.Raw + } + if ark != nil { + att.CertificateChain.ArkCert = ark.Raw + } + // Otherwise, retrieve it from AMD KDS. + if att.CertificateChain.AskCert == nil || att.CertificateChain.ArkCert == nil { + logger.Infof( + "Certificate chain not fully present (ARK present: %t, ASK present: %t), falling back to retrieving it from AMD KDS", + (att.CertificateChain.ArkCert != nil), + (att.CertificateChain.AskCert != nil), + ) + kdsCertChain, err := trust.GetProductChain(productName, abi.VcekReportSigner, getter) + if err != nil { + return nil, fmt.Errorf("retrieving certificate chain from AMD KDS: %w", err) + } + if att.CertificateChain.AskCert == nil { + att.CertificateChain.AskCert = kdsCertChain.Ask.Raw + } + if att.CertificateChain.ArkCert == nil { + att.CertificateChain.ArkCert = kdsCertChain.Ark.Raw + } } - if err = vcek.CheckSignatureFrom(ask); err != nil { - return nil, &vcekError{err} + return att, nil +} + +// parseCertChain parses the certificate chain from the instanceInfo into x509-formatted ASK and ARK certificates. +// If less than 2 certificates are present, only the present certificate is returned. +// If more than 2 certificates are present, an error is returned. +func (a *azureInstanceInfo) parseCertChain() (ask, ark *x509.Certificate, retErr error) { + rest := bytes.TrimSpace(a.CertChain) + + i := 1 + var block *pem.Block + for block, rest = pem.Decode(rest); block != nil; block, rest = pem.Decode(rest) { + if i > 2 { + retErr = fmt.Errorf("parse certificate %d: more than 2 certificates in chain", i) + return + } + + if block.Type != "CERTIFICATE" { + retErr = fmt.Errorf("parse certificate %d: expected PEM block type 'CERTIFICATE', got '%s'", i, block.Type) + return + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + retErr = fmt.Errorf("parse certificate %d: %w", i, err) + return + } + + // https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/57230.pdf + // Table 6 and 7 + switch cert.Subject.CommonName { + case "SEV-Milan": + ask = cert + case "ARK-Milan": + ark = cert + default: + retErr = fmt.Errorf("parse certificate %d: unexpected subject CN %s", i, cert.Subject.CommonName) + return + } + + i++ + } + + switch { + case i == 1: + retErr = fmt.Errorf("no PEM blocks found") + case len(rest) != 0: + retErr = fmt.Errorf("remaining PEM block is not a valid certificate: %s", rest) + } + + return +} + +// parseVCEK parses the VCEK certificate from the instanceInfo into an x509-formatted certificate. +// If the VCEK certificate is not present, nil is returned. +func (a *azureInstanceInfo) parseVCEK() (*x509.Certificate, error) { + newlinesTrimmed := bytes.TrimSpace(a.VCEK) + if len(newlinesTrimmed) == 0 { + // VCEK is not present. + return nil, nil + } + + block, rest := pem.Decode(newlinesTrimmed) + if block == nil { + return nil, fmt.Errorf("no PEM blocks found") + } + if len(rest) != 0 { + return nil, fmt.Errorf("received more data than expected") + } + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("expected PEM block type 'CERTIFICATE', got '%s'", block.Type) + } + + vcek, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parsing VCEK certificate: %w", err) } return vcek, nil } -func (v *Validator) validateSNPReport( - ctx context.Context, cert *x509.Certificate, report snpAttestationReport, maaToken string, extraData []byte, -) error { - if report.Policy.Debug() { - return errDebugEnabled - } - - if !report.CommittedTCB.isVersion(v.config.BootloaderVersion.Value, v.config.TEEVersion.Value, v.config.SNPVersion.Value, v.config.MicrocodeVersion.Value) { - return &versionError{"COMMITTED_TCB", report.CommittedTCB} - } - if report.LaunchTCB != report.CommittedTCB { - return &versionError{"LAUNCH_TCB", report.LaunchTCB} - } - if !report.CommittedTCB.supersededBy(report.CurrentTCB) { - return &versionError{"CURRENT_TCB", report.CurrentTCB} - } - - if err := validateVCEKExtensions(cert, report); err != nil { - return fmt.Errorf("mismatching vcek extensions: %w", err) - } - - sigR := report.Signature.R[:] - sigS := report.Signature.S[:] - - // Table 107 in https://www.amd.com/system/files/TechDocs/56860.pdf mentions little endian signature components. - // They come out of the certificate as big endian. - reverseEndian(sigR) - reverseEndian(sigS) - - rParam := new(big.Int).SetBytes(sigR) - sParam := new(big.Int).SetBytes(sigS) - sequence := ecdsaSig{rParam, sParam} - sigEncoded, err := asn1.Marshal(sequence) - if err != nil { - return fmt.Errorf("marshalling ecdsa signature: %w", err) - } - - buf := new(bytes.Buffer) - if err = binary.Write(buf, binary.LittleEndian, report); err != nil { - return fmt.Errorf("writing report to buf: %w", err) - } - // signature is only calculated from 0x0 to 0x2a0 - if err := cert.CheckSignature(x509.ECDSAWithSHA384, buf.Bytes()[:0x2a0], sigEncoded); err != nil { - return &signatureError{err} - } - - hasExpectedIDKeyDigest := false - for _, digest := range v.config.FirmwareSignerConfig.AcceptedKeyDigests { - if bytes.Equal(digest, report.IDKeyDigest[:]) { - hasExpectedIDKeyDigest = true - break - } - } - - if !hasExpectedIDKeyDigest { - switch v.config.FirmwareSignerConfig.EnforcementPolicy { - case idkeydigest.MAAFallback: - v.log.Infof( - "configured idkeydigests %x don't contain reported idkeydigest %x, falling back to MAA validation", - v.config.FirmwareSignerConfig.AcceptedKeyDigests, - report.IDKeyDigest[:], - ) - return v.maa.validateToken(ctx, v.config.FirmwareSignerConfig.MAAURL, maaToken, extraData) - case idkeydigest.WarnOnly: - v.log.Warnf( - "configured idkeydigests %x don't contain reported idkeydigest %x", - v.config.FirmwareSignerConfig.AcceptedKeyDigests, - report.IDKeyDigest[:], - ) - default: - return &idKeyError{report.IDKeyDigest[:], v.config.FirmwareSignerConfig.AcceptedKeyDigests} - } - } - - return nil -} - -// validateVCEKExtensions checks that the certificate extension values in cert match the values described in report. -func validateVCEKExtensions(cert *x509.Certificate, report snpAttestationReport) error { - var certVersion int - for _, extension := range cert.Extensions { - switch extension.Id.String() { - // check bootloader version - case "1.3.6.1.4.1.3704.1.3.1": - { - _, err := asn1.Unmarshal(extension.Value, &certVersion) - if err != nil { - return fmt.Errorf("unmarshalling bootloader version: %w", err) - } - if certVersion != int(report.CommittedTCB.Bootloader) { - return fmt.Errorf("bootloader version %d from report does not match VCEK version %d", int(report.CommittedTCB.Bootloader), certVersion) - } - } - // check TEE version - case "1.3.6.1.4.1.3704.1.3.2": - { - _, err := asn1.Unmarshal(extension.Value, &certVersion) - if err != nil { - return fmt.Errorf("unmarshalling tee version: %w", err) - } - if certVersion != int(report.CommittedTCB.TEE) { - return fmt.Errorf("bootloader version %d from report does not match VCEK version %d", int(report.CommittedTCB.TEE), certVersion) - } - } - // check SNP Firmware version - case "1.3.6.1.4.1.3704.1.3.3": - { - _, err := asn1.Unmarshal(extension.Value, &certVersion) - if err != nil { - return fmt.Errorf("unmarshalling snp version: %w", err) - } - if certVersion != int(report.CommittedTCB.SNP) { - return fmt.Errorf("bootloader version %d from report does not match VCEK version %d", int(report.CommittedTCB.SNP), certVersion) - } - } - // check microcode version - case "1.3.6.1.4.1.3704.1.3.8": - { - _, err := asn1.Unmarshal(extension.Value, &certVersion) - if err != nil { - return fmt.Errorf("unmarshalling microcode version: %w", err) - } - if certVersion != int(report.CommittedTCB.Microcode) { - return fmt.Errorf("bootloader version %d from report does not match VCEK version %d", int(report.CommittedTCB.Microcode), certVersion) - } - } - } - } - - return nil -} - -type azureInstanceInfo struct { - Vcek []byte - CertChain []byte - AttestationReport []byte - RuntimeData []byte - MAAToken string -} - // validateAk validates that the attestation key from the TPM is trustworthy. The steps are: // 1. runtime data read from the TPM has the same sha256 digest as reported in `report_data` of the SNP report. // 2. modulus reported in runtime data matches modulus from key at idx 0x81000003. @@ -336,84 +448,7 @@ type hclAkValidator interface { validateAk(runtimeDataRaw []byte, reportData []byte, rsaParameters *tpm2.RSAParams) error } -// Reference: https://github.com/AMDESE/sev-guest/blob/main/include/attestation.h -type snpAttestationReport struct { - Version uint32 // 0x000 - GuestSVN uint32 // 0x004 - Policy guestPolicy // 0x008 - FamilyID [16]byte // 0x010 - ImageID [16]byte // 0x020 - VMPL uint32 // 0x030 - SignatureAlgo uint32 // 0x034 - CurrentTCB tcbVersion // 0x038 - PlatformInfo uint64 // 0x040 - Flags uint32 // 0x048 - Reserved0 uint32 // 0x04C - ReportData [64]byte // 0x050 - Measurement [48]byte // 0x090 - HostData [32]byte // 0x0C0 - IDKeyDigest [48]byte // 0x0E0 - AuthorKeyDigest [48]byte // 0x110 - ReportID [32]byte // 0x140 - ReportIDMa [32]byte // 0x160 - ReportedTCB tcbVersion // 0x180 - _ [24]byte // 0x188 - ChipID [64]byte // 0x1A0 - CommittedTCB tcbVersion // 0x1E0 - CurrentBuild byte // 0x1E8 - CurrentMinor byte // 0x1E9 - CurrentMajor byte // 0x1EA - _ byte // 0x1EB - CommittedBuild byte // 0x1EC - CommittedMinor byte // 0x1ED - CommittedMajor byte // 0x1EE - _ byte // 0x1EF - LaunchTCB tcbVersion // 0x1F0 - _ [168]byte // 0x1F8 - Signature snpSignature // 0x2A0 -} - -type guestPolicy struct { - AbiMinor uint8 // 0x0 - AbiMajor uint8 // 0x8 - ContainerValue byte // 0x10 - encodes the following four values: - // Smt bool // 0x10 - bit 0 in 'ContainerValue'. - // _ bool // 0x11 - bit 1 in 'ContainerValue'. - // MigrateMa bool // 0x12 - bit 2 in 'ContainerValue'. - // Debug bool // 0x13 - bit 3 in 'ContainerValue'. - // SingleSocket bool // 0x14 - bit 4 in 'ContainerValue'. - _ [5]byte // 0x15 -} - -func (g *guestPolicy) Debug() bool { - return (g.ContainerValue & 0b00001000) != 0 -} - -type tcbVersion struct { - Bootloader uint8 // 0x0 - TEE uint8 // 0x10 - _ [4]byte // 0x2F - SNP uint8 // 0x37 - Microcode uint8 // 0x3F -} - -func (t *tcbVersion) isVersion(expectedBootloader, expectedTEE, expectedSNP, expectedMicrocode uint8) bool { - return t.Bootloader >= expectedBootloader && t.TEE >= expectedTEE && t.SNP >= expectedSNP && t.Microcode >= expectedMicrocode -} - -func (t *tcbVersion) supersededBy(new tcbVersion) bool { - return new.Bootloader >= t.Bootloader && new.TEE >= t.TEE && new.SNP >= t.SNP && new.Microcode >= t.Microcode -} - -type snpSignature struct { - R [72]byte - S [72]byte - Reserved [512 - 144]byte -} -type ecdsaSig struct { - R, S *big.Int -} - +// akPub are the public parameters of an RSA attestation key. type akPub struct { E string N string diff --git a/internal/attestation/azure/snp/validator_test.go b/internal/attestation/azure/snp/validator_test.go index 3ceb00843..03f36ba9d 100644 --- a/internal/attestation/azure/snp/validator_test.go +++ b/internal/attestation/azure/snp/validator_test.go @@ -17,13 +17,22 @@ import ( "errors" "fmt" "os" + "regexp" + "strings" "testing" + "github.com/edgelesssys/constellation/v2/internal/attestation" + "github.com/edgelesssys/constellation/v2/internal/attestation/azure/snp/testdata" "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest" "github.com/edgelesssys/constellation/v2/internal/attestation/simulator" "github.com/edgelesssys/constellation/v2/internal/attestation/vtpm" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/logger" + "github.com/google/go-sev-guest/abi" + "github.com/google/go-sev-guest/kds" + spb "github.com/google/go-sev-guest/proto/sevsnp" + "github.com/google/go-sev-guest/validate" + "github.com/google/go-sev-guest/verify" "github.com/google/go-tpm-tools/client" "github.com/google/go-tpm-tools/proto/attest" "github.com/google/go-tpm/legacy/tpm2" @@ -31,171 +40,69 @@ import ( "github.com/stretchr/testify/require" ) -func TestTrustedKeyFromSNP(t *testing.T) { - cgo := os.Getenv("CGO_ENABLED") - if cgo == "0" { - t.Skip("skipping test because CGO is disabled and tpm simulator requires it") - } +// TestNewValidator tests the creation of a new validator. +func TestNewValidator(t *testing.T) { require := require.New(t) - tpm, err := simulator.OpenSimulatedTPM() - require.NoError(err) - defer tpm.Close() - key, err := client.AttestationKeyRSA(tpm) - require.NoError(err) - defer key.Close() - akPub, err := key.PublicArea().Encode() - require.NoError(err) - - defaultReport := "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000" - defaultRuntimeData := "7b226b657973223a5b7b226b6964223a2248434c416b507562222c226b65795f6f7073223a5b22656e6372797074225d2c226b7479223a22525341222c2265223a2241514142222c226e223a22747946717641414166324746656c6b5737566352684a6e4132597659364c6a427a65554e3276614d5a6e5a74685f74466e574d6b4b35415874757379434e656c337569703356475a7a54617a3558327447566a4772732d4d56486361703951647771555856573367394f515f74456269786378372d78626c554a516b474551666e626253646e5049326c764c7a4f73315a5f30766a65444178765351726d616773366e592d634a4157482d706744564a79487470735553735f5142576b6c617a44736f3557486d6e4d743973394d75696c57586f7830525379586e55656151796859316a753752545363526e5658754e7936377a5f454a6e774d393264727746623841556430534a5f396f687645596c34615a52444543476f3056726a635348552d4a474a6575574335566844425235454f6f4356424267716539653833765f6c4a784933574c65326f7653495a49497a416d625351227d5d2c22766d2d636f6e66696775726174696f6e223a7b22636f6e736f6c652d656e61626c6564223a747275652c2263757272656e742d74696d65223a313636313435353339312c227365637572652d626f6f74223a66616c73652c2274706d2d656e61626c6564223a747275652c22766d556e697175654964223a2242364339384333422d344543372d344441362d424432462d374439384432304437423735227d7d" - defaultVCEK := "-----BEGIN CERTIFICATE-----\nMIIFTDCCAvugAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAgUA\noRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATCjAwIBATB7MRQwEgYD\nVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDASBgNVBAcMC1NhbnRhIENs\nYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5jZWQgTWljcm8gRGV2aWNl\nczESMBAGA1UEAwwJU0VWLU1pbGFuMB4XDTIyMDYyOTE2MzEzMFoXDTI5MDYyOTE2\nMzEzMFowejEUMBIGA1UECwwLRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYD\nVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2Vk\nIE1pY3JvIERldmljZXMxETAPBgNVBAMMCFNFVi1WQ0VLMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAEhPX8Cl9uA7PxqNGzeqamJNYJLx/VFE/s3+8qOWtaztKNcn1PaAI4\nndE+yaVfMHsiA8CLTylumpWXcVBHPYV9kPEVrtozhvrrT5Oii9OpZPYHJ7/WPVmM\nJ3K8/Iz3AshTo4IBFjCCARIwEAYJKwYBBAGceAEBBAMCAQAwFwYJKwYBBAGceAEC\nBAoWCE1pbGFuLUIwMBEGCisGAQQBnHgBAwEEAwIBAjARBgorBgEEAZx4AQMCBAMC\nAQAwEQYKKwYBBAGceAEDBAQDAgEAMBEGCisGAQQBnHgBAwUEAwIBADARBgorBgEE\nAZx4AQMGBAMCAQAwEQYKKwYBBAGceAEDBwQDAgEAMBEGCisGAQQBnHgBAwMEAwIB\nBjARBgorBgEEAZx4AQMIBAMCAV0wTQYJKwYBBAGceAEEBECeRKrvAs/Kb926ymac\nbP0p4auNl+vJOYVxKKy7E7h0DfMUNtNOhuX4rgzf6zoOGF20beysF2zHfXYcIqG5\n3PJbMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0B\nAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBA4ICAQBXXzX8w+z06JNKLVAa9vyE\njC69c7uvfTPScqLzOCV+S8yZ7Ibpn6gdRcgn5s3F7uerVs9/8mq+rDpMzLTVxLei\nYAW9jDS9VdEgfUp3GzzL1g3zsWNZPpWuAu0Cw1V7KnQ9kiGsJMRKerx8QLrm+aAH\nOiob4XHl2naUx9aILzCLbNgLBdh6Tw2XkGj8NB9O7kNQoINEz6U+cAJL5LWzuoYt\nW1IJkYUEMydvLImFHeFIFtB2wI4mTSuCjtb/pBUeRdvDm5dmY/VPvh+CkvCeXNze\nHPZ8vcQ+ZZNS44O9rMnSUOtRFZb3ow3atXsx53Gy9rp41Bd0OZgSMrnHH74lDQX0\nkkNP+UrRYs66q0gJaSZglzkWfHLtAGfuRh9XyBh4kBgHcjF1Qh6frTpotX9t+0V/\nQZv3KjPVMsGaUN407WHEoAl6qX6TSS/An2EdXgqbhXS5O81gzatWDTcT2D3VJG1N\nHYtkh1J5WmrFTphc7OhxmVk7l3UkWPyS8Oi8be2y8Q4x0wgviZn5eOa/djpHoarW\nLS91KKPZXGyXlj49TlCjbl4RfyKYOd/HqgAYYdtqBe84AyJQRvuD5gWmdBzagncb\nyKjs6tYr74aAGnAqulp+yqvrzb7teUQmCMkROfzFjYZmLByqw6UGRdHgCf8hOzmO\nch4hf9cHRLAUJpqynRmb+g==\n-----END CERTIFICATE-----\n" - defaultCertChain := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n" - defaultIDKeyDigestOld, err := hex.DecodeString("57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1") - require.NoError(err) - defaultIDKeyDigest := idkeydigest.NewList([][]byte{defaultIDKeyDigestOld}) - testCases := map[string]struct { - report string - runtimeData string - vcek string - certChain string - idkeydigests idkeydigest.List - enforceIDKeyDigest idkeydigest.Enforcement - wantErr bool - assertCorrectError func(error) + cfg *config.AzureSEVSNP + logger attestation.Logger }{ "success": { - report: defaultReport, - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, + cfg: config.DefaultForAzureSEVSNP(), + logger: logger.NewTest(t), }, - "invalid report signature": { - report: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000", - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &signatureError{} - assert.ErrorAs(t, err, &target) - }, + "nil logger": { + cfg: config.DefaultForAzureSEVSNP(), + logger: nil, }, - "invalid vcek": { - report: defaultReport, - runtimeData: defaultRuntimeData, - vcek: "-----BEGIN CERTIFICATE-----\nMIIFTDCCAvugAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAgUA\noRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATCjAwIBATB7MRQwEgYD\nVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDASBgNVBAcMC1NhbnRhIENs\nYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5jZWQgTWljcm8gRGV2aWNl\nczESMBAGA1UEAwwJU0VWLU1pbGFuMB4XDTIyMDYxMTE2MjE0OFoXDTI5MDYxMTE2\nMjE0OFowejEUMBIGA1UECwwLRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYD\nVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2Vk\nIE1pY3JvIERldmljZXMxETAPBgNVBAMMCFNFVi1WQ0VLMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAEdBdzuRwdnQvH5MMutYl0GqQc6kwh0NRueQhDm00i5XLCgV0NLvlX\nrhKuomRLKFdyT9ddzcgZGYlB5lpc1MPZvOOKWAxsniZ1fB3EcMcbS5blPM3yl1Ca\nGzwBMEq/P7dfo4IBFjCCARIwEAYJKwYBBAGceAEBBAMCAQAwFwYJKwYBBAGceAEC\nBAoWCE1pbGFuLUIwMBEGCisGAQQBnHgBAwEEAwIBAjARBgorBgEEAZx4AQMCBAMC\nAQAwEQYKKwYBBAGceAEDBAQDAgEAMBEGCisGAQQBnHgBAwUEAwIBADARBgorBgEE\nAZx4AQMGBAMCAQAwEQYKKwYBBAGceAEDBwQDAgEAMBEGCisGAQQBnHgBAwMEAwIB\nBjARBgorBgEEAZx4AQMIBAMCAV0wTQYJKwYBBAGceAEEBEDTy4KCFroFQ6PWI7+Q\nTHqQj0c5tch4VsqwbhdisV/kXizUuNiEBniVILiO2mLY3zZYMYHKEDm3NbhCaVO+\nQOgSMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0B\nAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBA4ICAQBkge6Vsbnni2DTPrXw4To9\nSR6vwsgRKiUxyu/tB18DiDcjO/HpFa1l8COt6Gg690Hnn4ezYAIYw4co/SoJQ0+v\nerxiQqJJAHgpKQ3QqNdnESlyM9eZaZN5ND4S+gXtnFb4K42FzAAy6cyuXKVsrh8B\nuMJnK0sHm3+8qDUXz/NjL95kG/wGSB6LOSk0sll2VFKaolMmH+VhR4m6zO7z8/SA\nt/cPXsZ+/Me/ZP46WibHGHhvLD8kSuyVmt+SIlx9wjdRHqNBNtvx4VEMMZwJX2o+\n0T6nuZ4cnrHK18zdb+K8/3qCFprdHRDD5bo491fnIsAYGGIfcNmAz2uCI9j9TE6R\nGGS2k1jQgWls19nw/Ra++8Kf/roR6WVax8k2R8+XV9eRZ33TqDXAHSbGcZbynaEb\neo6V8MKwLbVNi/7MP6b90nEtvN0SLRbKCJvEn/iHUHQa9BnT14zeTJw2gR/uG+M5\nxC+q9+nKMhIAGOIyxpFp67XBJSSOJut9bmvaPpLIC+/Mr+GKiM+YMQHzYwH6fuDT\no8LVlmuDiOz78BzmD/zy3DaYWTkHourKa7x/DSwuF8MQkvquwEHwkuikpLyo+b54\nSzqt81FR21rUxbkaUv9urRyYfzZ3m3ogApAveGdYPo1y4sl1FPd8X5+aVeghGyXU\nL9lHQ8+Y53Pf/ZQ/gYI0dQ==\n-----END CERTIFICATE-----\n", - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &vcekError{} - assert.ErrorAs(t, err, &target) - }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + validator := NewValidator(tc.cfg, tc.logger) + require.NotNil(validator) + require.NotNil(validator.log) + }) + } +} + +// TestParseCertChain tests the parsing of the certificate chain. +func TestParseCertChain(t *testing.T) { + defaultCertChain := testdata.CertChain + askOnly := strings.Split(string(defaultCertChain), "-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----" + arkOnly := strings.Split(string(defaultCertChain), "-----END CERTIFICATE-----")[1] + "-----END CERTIFICATE-----" + + testCases := map[string]struct { + certChain []byte + wantAsk bool + wantArk bool + wantErr bool + }{ + "success": { + certChain: defaultCertChain, + wantAsk: true, + wantArk: true, }, - "malformed ask": { - report: defaultReport, - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGiTCCBDigAwIBAgIDAQABMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTgyNDIwWhcNNDUxMDIy\nMTgyNDIwWjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJU0VWLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEAnU2drrNTfbhNQIllf+W2y+ROCbSzId1aKZft\n2T9zjZQOzjGccl17i1mIKWl7NTcB0VYXt3JxZSzOZjsjLNVAEN2MGj9TiedL+Qew\nKZX0JmQEuYjm+WKksLtxgdLp9E7EZNwNDqV1r0qRP5tB8OWkyQbIdLeu4aCz7j/S\nl1FkBytev9sbFGzt7cwnjzi9m7noqsk+uRVBp3+In35QPdcj8YflEmnHBNvuUDJh\nLCJMW8KOjP6++Phbs3iCitJcANEtW4qTNFoKW3CHlbcSCjTM8KsNbUx3A8ek5EVL\njZWH1pt9E3TfpR6XyfQKnY6kl5aEIPwdW3eFYaqCFPrIo9pQT6WuDSP4JCYJbZne\nKKIbZjzXkJt3NQG32EukYImBb9SCkm9+fS5LZFg9ojzubMX3+NkBoSXI7OPvnHMx\njup9mw5se6QUV7GqpCA2TNypolmuQ+cAaxV7JqHE8dl9pWf+Y3arb+9iiFCwFt4l\nAlJw5D0CTRTC1Y5YWFDBCrA/vGnmTnqG8C+jjUAS7cjjR8q4OPhyDmJRPnaC/ZG5\nuP0K0z6GoO/3uen9wqshCuHegLTpOeHEJRKrQFr4PVIwVOB0+ebO5FgoyOw43nyF\nD5UKBDxEB4BKo/0uAiKHLRvvgLbORbU8KARIs1EoqEjmF8UtrmQWV2hUjwzqwvHF\nei8rPxMCAwEAAaOBozCBoDAdBgNVHQ4EFgQUO8ZuGCrD/T1iZEib47dHLLT8v/gw\nHwYDVR0jBBgwFoAUhawa0UP3yKxV1MUdQUir1XhK1FMwEgYDVR0TAQH/BAgwBgEB\n/wIBADAOBgNVHQ8BAf8EBAMCAQQwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cHM6Ly9r\nZHNpbnRmLmFtZC5jb20vdmNlay92MS9NaWxhbi9jcmwwRgYJKoZIhvcNAQEKMDmg\nDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKID\nAgEwowMCAQEDggIBAIgeUQScAf3lDYqgWU1VtlDbmIN8S2dC5kmQzsZ/HtAjQnLE\nPI1jh3gJbLxL6gf3K8jxctzOWnkYcbdfMOOr28KT35IaAR20rekKRFptTHhe+DFr\n3AFzZLDD7cWK29/GpPitPJDKCvI7A4Ug06rk7J0zBe1fz/qe4i2/F12rvfwCGYhc\nRxPy7QF3q8fR6GCJdB1UQ5SlwCjFxD4uezURztIlIAjMkt7DFvKRh+2zK+5plVGG\nFsjDJtMz2ud9y0pvOE4j3dH5IW9jGxaSGStqNrabnnpF236ETr1/a43b8FFKL5QN\nmt8Vr9xnXRpznqCRvqjr+kVrb6dlfuTlliXeQTMlBoRWFJORL8AcBJxGZ4K2mXft\nl1jU5TLeh5KXL9NW7a/qAOIUs2FiOhqrtzAhJRg9Ij8QkQ9Pk+cKGzw6El3T3kFr\nEg6zkxmvMuabZOsdKfRkWfhH2ZKcTlDfmH1H0zq0Q2bG3uvaVdiCtFY1LlWyB38J\nS2fNsR/Py6t5brEJCFNvzaDky6KeC4ion/cVgUai7zzS3bGQWzKDKU35SqNU2WkP\nI8xCZ00WtIiKKFnXWUQxvlKmmgZBIYPe01zD0N8atFxmWiSnfJl690B9rJpNR/fI\najxCW3Seiws6r1Zm+tCuVbMiNtpS9ThjNX4uve5thyfE2DgoxRFvY1CsoF5M\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n", - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &askError{} - assert.ErrorAs(t, err, &target) - }, + "empty cert chain": { + certChain: []byte{}, + wantErr: true, }, - "invalid runtime data digest": { - report: defaultReport, - runtimeData: "7b226b657973223a5b7b226b6964223a2248434c426b507562222c226b65795f6f7073223a5b22656e6372797074225d2c226b7479223a22525341222c2265223a2241514142222c226e223a22747946717641414166324746656c6b5737566352684a6e4132597659364c6a427a65554e3276614d5a6e5a74685f74466e574d6b4b35415874757379434e656c337569703356475a7a54617a3558327447566a4772732d4d56486361703951647771555856573367394f515f74456269786378372d78626c554a516b474551666e626253646e5049326c764c7a4f73315a5f30766a65444178765351726d616773366e592d634a4157482d706744564a79487470735553735f5142576b6c617a44736f3557486d6e4d743973394d75696c57586f7830525379586e55656151796859316a753752545363526e5658754e7936377a5f454a6e774d393264727746623841556430534a5f396f687645596c34615a52444543476f3056726a635348552d4a474a6575574335566844425235454f6f4356424267716539653833765f6c4a784933574c65326f7653495a49497a416d625351227d5d2c22766d2d636f6e66696775726174696f6e223a7b22636f6e736f6c652d656e61626c6564223a747275652c2263757272656e742d74696d65223a313636313435353339312c227365637572652d626f6f74223a66616c73652c2274706d2d656e61626c6564223a747275652c22766d556e697175654964223a2242364339384333422d344543372d344441362d424432462d374439384432304437423735227d7d", - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := errors.New("unexpected runtimeData digest in TPM") - assert.ErrorAs(t, err, &target) - }, + "more than two certificates": { + certChain: append(defaultCertChain, defaultCertChain...), + wantErr: true, }, - "invalid idkeydigest": { - report: defaultReport, - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: idkeydigest.List{[]byte{0x00}}, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &idKeyError{} - assert.ErrorAs(t, err, &target) - }, + "invalid certificate": { + certChain: []byte("invalid"), + wantErr: true, }, - "don't enforce idkeydigest": { - report: defaultReport, - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: idkeydigest.List{[]byte{0x00}}, - enforceIDKeyDigest: idkeydigest.WarnOnly, + "ark missing": { + certChain: []byte(askOnly), + wantAsk: true, }, - "unsupported microcode version": { - report: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065c0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000", - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &versionError{} - assert.ErrorAs(t, err, &target) - }, - }, - "current tcb older than committed tcb": { - report: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065c010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000", - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &versionError{} - assert.ErrorAs(t, err, &target) - }, - }, - "launch tcb != committed tcb": { - report: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000", - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - target := &versionError{} - assert.ErrorAs(t, err, &target) - }, - }, - "debugging allowed": { - report: "02000000020000001f000b000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000", - runtimeData: defaultRuntimeData, - vcek: defaultVCEK, - certChain: defaultCertChain, - idkeydigests: defaultIDKeyDigest, - enforceIDKeyDigest: idkeydigest.Equal, - wantErr: true, - assertCorrectError: func(err error) { - assert.ErrorIs(t, err, errDebugEnabled) - }, + "ask missing": { + certChain: []byte(arkOnly), + wantArk: true, }, } @@ -203,49 +110,312 @@ func TestTrustedKeyFromSNP(t *testing.T) { t.Run(name, func(t *testing.T) { assert := assert.New(t) - instanceInfo, err := newStubAzureInstanceInfo(tc.vcek, tc.certChain, tc.report, tc.runtimeData) - assert.NoError(err) - - statement, err := json.Marshal(instanceInfo) - if err != nil { - assert.Error(err) + instanceInfo := &azureInstanceInfo{ + CertChain: tc.certChain, } - attDoc := vtpm.AttestationDocument{ - InstanceInfo: statement, - Attestation: &attest.Attestation{ - AkPub: akPub, - }, - } - - cfg := config.DefaultForAzureSEVSNP() - cfg.FirmwareSignerConfig = config.SNPFirmwareSignerConfig{ - AcceptedKeyDigests: tc.idkeydigests, - EnforcementPolicy: tc.enforceIDKeyDigest, - } - - validator := &Validator{ - hclValidator: &instanceInfo, - config: cfg, - log: logger.NewTest(t), - } - - key, err := validator.getTrustedKey(context.Background(), attDoc, nil) + ask, ark, err := instanceInfo.parseCertChain() if tc.wantErr { - tc.assertCorrectError(err) + assert.Error(err) } else { assert.NoError(err) - assert.NotNil(key) + assert.Equal(tc.wantAsk, ask != nil) + assert.Equal(tc.wantArk, ark != nil) } }) } } +// TestParseVCEK tests the parsing of the VCEK certificate. +func TestParseVCEK(t *testing.T) { + testCases := map[string]struct { + VCEK []byte + wantVCEK bool + wantErr bool + }{ + "success": { + VCEK: testdata.AzureThimVCEK, + wantVCEK: true, + }, + "empty": { + VCEK: []byte{}, + }, + "malformed": { + VCEK: testdata.AzureThimVCEK[:len(testdata.AzureThimVCEK)-100], + wantErr: true, + }, + "invalid": { + VCEK: []byte("invalid"), + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + instanceInfo := &azureInstanceInfo{ + VCEK: tc.VCEK, + } + + vcek, err := instanceInfo.parseVCEK() + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + assert.Equal(tc.wantVCEK, vcek != nil) + } + }) + } +} + +// TestInstanceInfoAttestation tests the basic unmarshalling of the attestation report. +func TestInstanceInfoAttestation(t *testing.T) { + defaultReport := testdata.AttestationReport + cfg := config.DefaultForAzureSEVSNP() + + testCases := map[string]struct { + report []byte + vcek []byte + certChain []byte + getter *stubHTTPSGetter + wantErr bool + }{ + "success": { + report: defaultReport, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + }, + "retrieve vcek": { + report: defaultReport, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + vcekResponse: testdata.AmdKdsVCEK, + wantVcekRequest: true, + }, + nil, + ), + }, + "retrieve certchain": { + report: defaultReport, + vcek: testdata.AzureThimVCEK, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + certChainResponse: testdata.CertChain, + wantCertChainRequest: true, + }, + nil, + ), + }, + "retrieve vcek and certchain": { + report: defaultReport, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + certChainResponse: testdata.CertChain, + vcekResponse: testdata.AmdKdsVCEK, + wantCertChainRequest: true, + wantVcekRequest: true, + }, + nil, + ), + }, + "report too short": { + report: defaultReport[:len(defaultReport)-100], + wantErr: true, + }, + "corrupted report": { + report: defaultReport[10 : len(defaultReport)-10], + wantErr: true, + }, + "certificate fetch error": { + report: defaultReport, + getter: newStubHTTPSGetter(nil, assert.AnError), + wantErr: true, + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + instanceInfo := azureInstanceInfo{ + AttestationReport: tc.report, + CertChain: tc.certChain, + VCEK: tc.vcek, + } + + att, err := instanceInfo.attestationWithCerts(logger.NewTest(t), tc.getter) + if tc.wantErr { + assert.Error(err) + } else { + require.NoError(err) + assert.NotNil(att) + assert.NotNil(att.CertificateChain) + assert.NotNil(att.Report) + + assert.Equal(hex.EncodeToString(att.Report.IdKeyDigest[:]), "57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1") + + // This is a canary for us: If this fails in the future we possibly downgraded a SVN. + // See https://github.com/google/go-sev-guest/blob/14ac50e9ffcc05cd1d12247b710c65093beedb58/validate/validate.go#L336 for decomposition of the values. + tcbValues := kds.DecomposeTCBVersion(kds.TCBVersion(att.Report.GetLaunchTcb())) + assert.True(tcbValues.BlSpl >= cfg.BootloaderVersion.Value) + assert.True(tcbValues.TeeSpl >= cfg.TEEVersion.Value) + assert.True(tcbValues.SnpSpl >= cfg.SNPVersion.Value) + assert.True(tcbValues.UcodeSpl >= cfg.MicrocodeVersion.Value) + } + }) + } +} + +type stubHTTPSGetter struct { + urlResponseMatcher *urlResponseMatcher // maps responses to requested URLs + err error +} + +func newStubHTTPSGetter(urlResponseMatcher *urlResponseMatcher, err error) *stubHTTPSGetter { + return &stubHTTPSGetter{ + urlResponseMatcher: urlResponseMatcher, + err: err, + } +} + +func (s *stubHTTPSGetter) Get(url string) ([]byte, error) { + if s.err != nil { + return nil, s.err + } + return s.urlResponseMatcher.match(url) +} + +type urlResponseMatcher struct { + certChainResponse []byte + wantCertChainRequest bool + vcekResponse []byte + wantVcekRequest bool +} + +func (m *urlResponseMatcher) match(url string) ([]byte, error) { + switch { + case url == "https://kdsintf.amd.com/vcek/v1/Milan/cert_chain": + if !m.wantCertChainRequest { + return nil, fmt.Errorf("unexpected cert_chain request") + } + return m.certChainResponse, nil + case regexp.MustCompile(`https:\/\/kdsintf.amd.com\/vcek\/v1\/Milan\/.*`).MatchString(url): + if !m.wantVcekRequest { + return nil, fmt.Errorf("unexpected VCEK request") + } + return m.vcekResponse, nil + default: + return nil, fmt.Errorf("unexpected URL: %s", url) + } +} + +// TestCheckIDKeyDigest tests validation of an IDKeyDigest under different enforcement policies. +func TestCheckIDKeyDigest(t *testing.T) { + cfgWithAcceptedIDKeyDigests := func(enforcementPolicy idkeydigest.Enforcement, digestStrings []string) *config.AzureSEVSNP { + digests := idkeydigest.List{} + for _, digest := range digestStrings { + digests = append(digests, []byte(digest)) + } + cfg := config.DefaultForAzureSEVSNP() + cfg.FirmwareSignerConfig.AcceptedKeyDigests = digests + cfg.FirmwareSignerConfig.EnforcementPolicy = enforcementPolicy + return cfg + } + reportWithIDKeyDigest := func(idKeyDigest string) *spb.Attestation { + report := &spb.Attestation{} + report.Report = &spb.Report{} + report.Report.IdKeyDigest = []byte(idKeyDigest) + return report + } + newTestValidator := func(cfg *config.AzureSEVSNP, validateTokenErr error) *Validator { + validator := NewValidator(cfg, logger.NewTest(t)) + validator.maa = &stubMaaValidator{ + validateTokenErr: validateTokenErr, + } + return validator + } + + testCases := map[string]struct { + idKeyDigest string + acceptedIDKeyDigests []string + enforcementPolicy idkeydigest.Enforcement + validateMaaTokenErr error + wantErr bool + }{ + "matching digest": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{"test"}, + }, + "no accepted digests": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{}, + wantErr: true, + }, + "mismatching digest, enforce": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{"other"}, + wantErr: true, + }, + "mismatching digest, maaFallback": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{"other"}, + enforcementPolicy: idkeydigest.MAAFallback, + }, + "mismatching digest, maaFallback errors": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{"other"}, + enforcementPolicy: idkeydigest.MAAFallback, + validateMaaTokenErr: errors.New("maa fallback failed"), + wantErr: true, + }, + "mismatching digest, warnOnly": { + idKeyDigest: "test", + acceptedIDKeyDigests: []string{"other"}, + enforcementPolicy: idkeydigest.WarnOnly, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + require := require.New(t) + + cfg := cfgWithAcceptedIDKeyDigests(tc.enforcementPolicy, tc.acceptedIDKeyDigests) + report := reportWithIDKeyDigest(tc.idKeyDigest) + validator := newTestValidator(cfg, tc.validateMaaTokenErr) + + err := validator.checkIDKeyDigest(context.Background(), report, "", nil) + if tc.wantErr { + require.Error(err) + } else { + require.NoError(err) + } + }) + } +} + +type stubMaaValidator struct { + validateTokenErr error +} + +func (v *stubMaaValidator) validateToken(_ context.Context, _ string, _ string, _ []byte) error { + return v.validateTokenErr +} + +// TestValidateAk tests the attestation key validation with a simulated TPM device. func TestValidateAk(t *testing.T) { cgo := os.Getenv("CGO_ENABLED") if cgo == "0" { t.Skip("skipping test because CGO is disabled and tpm simulator requires it") } + + int32ToBytes := func(val uint32) []byte { + r := make([]byte, 4) + binary.PutUvarint(r, uint64(val)) + return r + } + require := require.New(t) tpm, err := simulator.OpenSimulatedTPM() @@ -255,7 +425,7 @@ func TestValidateAk(t *testing.T) { require.NoError(err) defer key.Close() - e := base64.RawURLEncoding.EncodeToString(int32ToByte(key.PublicArea().RSAParameters.ExponentRaw)) + e := base64.RawURLEncoding.EncodeToString(int32ToBytes(key.PublicArea().RSAParameters.ExponentRaw)) n := base64.RawURLEncoding.EncodeToString(key.PublicArea().RSAParameters.ModulusRaw) ak := akPub{E: e, N: n} @@ -333,59 +503,500 @@ func TestValidateAk(t *testing.T) { } } -func int32ToByte(val uint32) []byte { - r := make([]byte, 4) - binary.PutUvarint(r, uint64(val)) - return r -} +// TestGetTrustedKey tests the verification and validation of attestation report. +func TestTrustedKeyFromSNP(t *testing.T) { + cgo := os.Getenv("CGO_ENABLED") + if cgo == "0" { + t.Skip("skipping test because CGO is disabled and tpm simulator requires it") + } + require := require.New(t) -func TestValidateAzureCVM(t *testing.T) { - assert.NoError(t, validateCVM(vtpm.AttestationDocument{}, nil)) -} + tpm, err := simulator.OpenSimulatedTPM() + require.NoError(err) + defer tpm.Close() + key, err := client.AttestationKeyRSA(tpm) + require.NoError(err) + defer key.Close() + akPub, err := key.PublicArea().Encode() + require.NoError(err) + + defaultCfg := config.DefaultForAzureSEVSNP() + defaultReport := hex.EncodeToString(testdata.AttestationReport) + defaultRuntimeData := hex.EncodeToString(testdata.RuntimeData) + defaultIDKeyDigestOld, err := hex.DecodeString("57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1") + require.NoError(err) + defaultIDKeyDigest := idkeydigest.NewList([][]byte{defaultIDKeyDigestOld}) + defaultVerifier := &stubAttestationVerifier{} + skipVerifier := &stubAttestationVerifier{skipCheck: true} + defaultValidator := &stubAttestationValidator{} + + // reportTransformer unpacks the hex-encoded report, applies the given transformations and re-encodes it. + reportTransformer := func(reportHex string, transformations func(*spb.Report)) string { + rawReport, err := hex.DecodeString(reportHex) + require.NoError(err) + report, err := abi.ReportToProto(rawReport) + require.NoError(err) + transformations(report) + reportBytes, err := abi.ReportToAbiBytes(report) + require.NoError(err) + return hex.EncodeToString(reportBytes) + } -func TestNewSNPReportFromBytes(t *testing.T) { testCases := map[string]struct { - raw string - wantErr bool + report string + runtimeData string + vcek []byte + certChain []byte + acceptedIDKeyDigests idkeydigest.List + enforcementPolicy idkeydigest.Enforcement + getter *stubHTTPSGetter + verifier *stubAttestationVerifier + validator *stubAttestationValidator + wantErr bool + assertion func(*assert.Assertions, error) }{ "success": { - raw: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d01000000000000000000000000000000d288b28c3e9640f4e8167c742c1dc9487dc7e2b23b3f52c96d0fb07ce60c675400000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c45c7e7a4a581d28d7f2ba99de06efc0282ace9ab62eb97044ce8aa6b215071affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d000000000000000000000000000000000000000000000000d3cb828216ba0543a3d623bf904c7a908f4739b5c87856cab06e1762b15fe45e2cd4b8d88406789520b88eda62d8df36583181ca1039b735b8426953be40e812020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b11a48bf77e60979777e25739acdf8b791ea9bab3ace88f173e3239acc657b02f418f5cc60615e36a95f4360334a9751000000000000000000000000000000000000000000000000c0280bf824034fbff4b18899f77f2557b98fa0bf3572d062bf860dbf9b9b498fd2a377f0209f6b993687f791981de71b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - wantErr: false, + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), }, - "too short": { - raw: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d01000000000000000000000000000000d288b28c3e9640f4e8167c742c1dc9487dc7e2b23b3f52c96d0fb07ce60c675400000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c45c7e7a4a581d28d7f2ba99de06efc0282ace9ab62eb97044ce8aa6b215071affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d000000000000000000000000000000000000000000000000d3cb828216ba0543a3d623bf904c7a908f4739b5c87856cab06e1762b15fe45e2cd4b8d88406789520b88eda62d8df36583181ca1039b735b8426953be40e812020000000000065d0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b11a48bf77e60979777e25739acdf8b791ea9bab3ace88f173e3239acc657b02f418f5cc60615e36a95f4360334a9751000000000000000000000000000000000000000000000000c0280bf824034fbff4b18899f77f2557b98fa0bf3572d062bf860dbf9b9b498fd2a377f0209f6b993687f791981de71b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "certificate fetch error": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + getter: newStubHTTPSGetter( + nil, + assert.AnError, + ), wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "retrieving VCEK certificate from AMD KDS") + }, + }, + "fetch vcek and certchain": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + vcekResponse: testdata.AmdKdsVCEK, + wantVcekRequest: true, + certChainResponse: testdata.CertChain, + wantCertChainRequest: true, + }, + nil, + ), + }, + "fetch vcek": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + vcekResponse: testdata.AmdKdsVCEK, + wantVcekRequest: true, + }, + nil, + ), + }, + "fetch certchain": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + certChainResponse: testdata.CertChain, + wantCertChainRequest: true, + }, + nil, + ), + }, + "invalid report signature": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + r.Signature = make([]byte, 512) + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "report signature verification error") + }, + }, + "invalid vcek": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: []byte("invalid"), + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + vcekResponse: []byte("invalid"), + wantVcekRequest: true, + }, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "could not interpret VCEK DER bytes: x509: malformed certificate") + }, + }, + "invalid certchain fall back to embedded": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: []byte("invalid"), + getter: newStubHTTPSGetter( + &urlResponseMatcher{ + certChainResponse: []byte("invalid"), + wantCertChainRequest: true, + }, + nil, + ), + }, + "invalid runtime data": { + report: defaultReport, + runtimeData: defaultRuntimeData[:len(defaultRuntimeData)-10], + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "validating HCLAkPub: unmarshalling json: unexpected end of JSON input") + }, + }, + "inacceptable idkeydigest (wrong size), enforce": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: idkeydigest.List{[]byte{0x00}}, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "bad hash size in TrustedIDKeyHashes") + }, + }, + "inacceptable idkeydigest (wrong value), enforce": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: idkeydigest.List{make([]byte, 48)}, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "report ID key not trusted") + }, + }, + "inacceptable idkeydigest, warn only": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: idkeydigest.List{[]byte{0x00}}, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + }, + "launch tcb < minimum launch tcb": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + launchTcb := kds.DecomposeTCBVersion(kds.TCBVersion(r.LaunchTcb)) + defaultCfg.MicrocodeVersion.Value = 10 + launchTcb.UcodeSpl = 9 + newLaunchTcb, err := kds.ComposeTCBParts(launchTcb) + require.NoError(err) + r.LaunchTcb = uint64(newLaunchTcb) + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "is lower than the policy minimum launch TCB") + }, + }, + "reported tcb < minimum tcb": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + reportedTcb := kds.DecomposeTCBVersion(kds.TCBVersion(r.ReportedTcb)) + reportedTcb.UcodeSpl = defaultCfg.MicrocodeVersion.Value - 1 + newReportedTcb, err := kds.ComposeTCBParts(reportedTcb) + require.NoError(err) + r.ReportedTcb = uint64(newReportedTcb) + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "is lower than the policy minimum TCB") + }, + }, + "current tcb < committed tcb": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + r.CurrentTcb = r.CommittedTcb - 1 + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "is lower than the report's COMMITTED_TCB") + }, + }, + "current tcb < tcb in vcek": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + currentTcb := kds.DecomposeTCBVersion(kds.TCBVersion(r.CurrentTcb)) + currentTcb.UcodeSpl = 0x5c // testdata.AzureThimVCEK has ucode version 0x5d + newCurrentTcb, err := kds.ComposeTCBParts(currentTcb) + require.NoError(err) + r.CurrentTcb = uint64(newCurrentTcb) + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "is lower than the TCB of the V[CL]EK certificate") + }, + }, + "reported tcb != tcb in vcek": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + r.ReportedTcb = uint64(0) + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.WarnOnly, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "does not match the TCB of the V[CL]EK certificate") + }, + }, + "vmpl != 0": { + report: reportTransformer(defaultReport, func(r *spb.Report) { + r.Vmpl = 1 + }), + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: skipVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: testdata.CertChain, + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "report VMPL 1 is not 0") + }, + }, + "invalid ASK": { + report: defaultReport, + runtimeData: defaultRuntimeData, + acceptedIDKeyDigests: defaultIDKeyDigest, + enforcementPolicy: idkeydigest.Equal, + verifier: defaultVerifier, + validator: defaultValidator, + vcek: testdata.AzureThimVCEK, + certChain: func() []byte { + c := make([]byte, len(testdata.CertChain)) + copy(c, testdata.CertChain) + c[1676] = 0x41 // somewhere in the ASK signature + return c + }(), + getter: newStubHTTPSGetter( + &urlResponseMatcher{}, + nil, + ), + wantErr: true, + assertion: func(assert *assert.Assertions, err error) { + assert.ErrorContains(err, "crypto/rsa: verification error") + }, }, } - cfg := config.DefaultForAzureSEVSNP() + for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) - instanceInfo, err := newStubAzureInstanceInfo("", "", tc.raw, "") + instanceInfo, err := newStubAzureInstanceInfo(tc.vcek, tc.certChain, tc.report, tc.runtimeData) assert.NoError(err) - report, err := newSNPReportFromBytes(instanceInfo.AttestationReport) - if tc.wantErr { + + statement, err := json.Marshal(instanceInfo) + if err != nil { assert.Error(err) + } + + attDoc := vtpm.AttestationDocument{ + InstanceInfo: statement, + Attestation: &attest.Attestation{ + AkPub: akPub, + }, + } + + defaultCfg.FirmwareSignerConfig = config.SNPFirmwareSignerConfig{ + AcceptedKeyDigests: tc.acceptedIDKeyDigests, + EnforcementPolicy: tc.enforcementPolicy, + } + + validator := &Validator{ + hclValidator: &instanceInfo, + config: defaultCfg, + log: logger.NewTest(t), + getter: tc.getter, + attestationVerifier: tc.verifier, + attestationValidator: tc.validator, + } + + key, err := validator.getTrustedKey(context.Background(), attDoc, nil) + if tc.wantErr { + require.Error(err) + if tc.assertion != nil { + tc.assertion(assert, err) + } } else { - assert.NoError(err) - assert.NotNil(report) - assert.Equal(hex.EncodeToString(report.IDKeyDigest[:]), "57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1") - // This is a canary for us: If this fails in the future we possibly downgraded a SVN. - assert.True(report.LaunchTCB.isVersion(cfg.BootloaderVersion.Value, cfg.TEEVersion.Value, cfg.SNPVersion.Value, cfg.MicrocodeVersion.Value)) + require.NoError(err) + assert.NotNil(key) } }) } } -type stubAzureInstanceInfo struct { - Vcek []byte - CertChain []byte - AttestationReport []byte - RuntimeData []byte +type stubAttestationVerifier struct { + skipCheck bool // whether the verification function should be called } -func newStubAzureInstanceInfo(vcek string, certChain string, report string, runtimeData string) (stubAzureInstanceInfo, error) { +// SNPAttestation verifies the VCEK certificate as well as the certificate chain of the attestation report. +func (v *stubAttestationVerifier) SNPAttestation(attestation *spb.Attestation, options *verify.Options) error { + if v.skipCheck { + return nil + } + return verify.SnpAttestation(attestation, options) +} + +type stubAttestationValidator struct { + skipCheck bool // whether the verification function should be called +} + +// SNPAttestation validates the attestation report against the given set of constraints. +func (v *stubAttestationValidator) SNPAttestation(attestation *spb.Attestation, options *validate.Options) error { + if v.skipCheck { + return nil + } + return validate.SnpAttestation(attestation, options) +} + +type stubAzureInstanceInfo struct { + AttestationReport []byte + RuntimeData []byte + VCEK []byte + CertChain []byte +} + +func newStubAzureInstanceInfo(vcek, certChain []byte, report, runtimeData string) (stubAzureInstanceInfo, error) { validReport, err := hex.DecodeString(report) if err != nil { return stubAzureInstanceInfo{}, fmt.Errorf("invalid hex string report: %s", err) @@ -397,10 +1008,10 @@ func newStubAzureInstanceInfo(vcek string, certChain string, report string, runt } return stubAzureInstanceInfo{ - Vcek: []byte(vcek), - CertChain: []byte(certChain), AttestationReport: validReport, RuntimeData: decodedRuntime, + VCEK: vcek, + CertChain: certChain, }, nil } diff --git a/operators/constellation-node-operator/go.mod b/operators/constellation-node-operator/go.mod index 237d2a41e..04295b7e3 100644 --- a/operators/constellation-node-operator/go.mod +++ b/operators/constellation-node-operator/go.mod @@ -83,7 +83,7 @@ require ( github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -106,12 +106,12 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.12.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.9.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/operators/constellation-node-operator/go.sum b/operators/constellation-node-operator/go.sum index 4f9415011..eb3d15883 100644 --- a/operators/constellation-node-operator/go.sum +++ b/operators/constellation-node-operator/go.sum @@ -222,8 +222,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -356,8 +356,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -497,12 +497,12 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -512,8 +512,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=