mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-23 14:39:40 -05:00
cli: fix unmarshalling of sev-snp attestation documents in constellation verify
(#3171)
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
e0f52b4acd
commit
9d99d05826
@ -114,6 +114,8 @@ go_library(
|
||||
"@com_github_google_go_tdx_guest//abi",
|
||||
"@com_github_google_go_tdx_guest//proto/tdx",
|
||||
"//internal/attestation/azure/tdx",
|
||||
"@com_github_google_go_sev_guest//proto/sevsnp",
|
||||
"@com_github_google_go_tpm_tools//proto/attest",
|
||||
] + select({
|
||||
"@io_bazel_rules_go//go/platform:android_amd64": [
|
||||
"@org_golang_x_sys//unix",
|
||||
|
@ -38,8 +38,10 @@ import (
|
||||
"github.com/edgelesssys/constellation/v2/internal/verify"
|
||||
"github.com/edgelesssys/constellation/v2/verify/verifyproto"
|
||||
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
"github.com/google/go-tdx-guest/abi"
|
||||
"github.com/google/go-tdx-guest/proto/tdx"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
tpmProto "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
@ -191,16 +193,22 @@ func (c *verifyCmd) verify(cmd *cobra.Command, verifyClient verifyClient, config
|
||||
switch c.flags.output {
|
||||
case "json":
|
||||
attDocOutput, err = formatJSON(cmd.Context(), rawAttestationDoc, attConfig, c.log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("printing attestation document: %w", err)
|
||||
}
|
||||
|
||||
case "raw":
|
||||
attDocOutput = fmt.Sprintf("Attestation Document:\n%s\n", rawAttestationDoc)
|
||||
|
||||
case "":
|
||||
attDocOutput, err = formatDefault(cmd.Context(), rawAttestationDoc, attConfig, c.log)
|
||||
if err != nil {
|
||||
return fmt.Errorf("printing attestation document: %w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid output value for formatter: %s", c.flags.output)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("printing attestation document: %w", err)
|
||||
}
|
||||
|
||||
cmd.Println(attDocOutput)
|
||||
cmd.PrintErrln("Verification OK")
|
||||
@ -242,10 +250,10 @@ func (c *verifyCmd) validateEndpointFlag(cmd *cobra.Command, stateFile *state.St
|
||||
}
|
||||
|
||||
// formatJSON returns the json formatted attestation doc.
|
||||
func formatJSON(ctx context.Context, docString string, attestationCfg config.AttestationCfg, log debugLog,
|
||||
func formatJSON(ctx context.Context, docString []byte, attestationCfg config.AttestationCfg, log debugLog,
|
||||
) (string, error) {
|
||||
var doc vtpm.AttestationDocument
|
||||
if err := json.Unmarshal([]byte(docString), &doc); err != nil {
|
||||
doc, err := unmarshalAttDoc(docString, attestationCfg.GetVariant())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unmarshalling attestation document: %w", err)
|
||||
}
|
||||
|
||||
@ -299,14 +307,14 @@ func tdxFormatJSON(instanceInfoRaw []byte, attestationCfg config.AttestationCfg)
|
||||
}
|
||||
|
||||
// format returns the formatted attestation doc.
|
||||
func formatDefault(ctx context.Context, docString string, attestationCfg config.AttestationCfg, log debugLog,
|
||||
func formatDefault(ctx context.Context, docString []byte, attestationCfg config.AttestationCfg, log debugLog,
|
||||
) (string, error) {
|
||||
b := &strings.Builder{}
|
||||
b.WriteString("Attestation Document:\n")
|
||||
|
||||
var doc vtpm.AttestationDocument
|
||||
if err := json.Unmarshal([]byte(docString), &doc); err != nil {
|
||||
return "", fmt.Errorf("unmarshal attestation document: %w", err)
|
||||
doc, err := unmarshalAttDoc(docString, attestationCfg.GetVariant())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unmarshalling attestation document: %w", err)
|
||||
}
|
||||
|
||||
if err := parseQuotes(b, doc.Attestation.Quotes, attestationCfg.GetMeasurements()); err != nil {
|
||||
@ -370,11 +378,11 @@ type constellationVerifier struct {
|
||||
// Verify retrieves an attestation statement from the Constellation and verifies it using the validator.
|
||||
func (v *constellationVerifier) Verify(
|
||||
ctx context.Context, endpoint string, req *verifyproto.GetAttestationRequest, validator atls.Validator,
|
||||
) (string, error) {
|
||||
) ([]byte, error) {
|
||||
v.log.Debug(fmt.Sprintf("Dialing endpoint: %q", endpoint))
|
||||
conn, err := v.dialer.DialInsecure(ctx, endpoint)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("dialing init server: %w", err)
|
||||
return nil, fmt.Errorf("dialing init server: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
@ -383,24 +391,24 @@ func (v *constellationVerifier) Verify(
|
||||
v.log.Debug("Sending attestation request")
|
||||
resp, err := client.GetAttestation(ctx, req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting attestation: %w", err)
|
||||
return nil, fmt.Errorf("getting attestation: %w", err)
|
||||
}
|
||||
|
||||
v.log.Debug("Verifying attestation")
|
||||
signedData, err := validator.Validate(ctx, resp.Attestation, req.Nonce)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("validating attestation: %w", err)
|
||||
return nil, fmt.Errorf("validating attestation: %w", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(signedData, []byte(constants.ConstellationVerifyServiceUserData)) {
|
||||
return "", errors.New("signed data in attestation does not match expected user data")
|
||||
return nil, errors.New("signed data in attestation does not match expected user data")
|
||||
}
|
||||
|
||||
return string(resp.Attestation), nil
|
||||
return resp.Attestation, nil
|
||||
}
|
||||
|
||||
type verifyClient interface {
|
||||
Verify(ctx context.Context, endpoint string, req *verifyproto.GetAttestationRequest, validator atls.Validator) (string, error)
|
||||
Verify(ctx context.Context, endpoint string, req *verifyproto.GetAttestationRequest, validator atls.Validator) ([]byte, error)
|
||||
}
|
||||
|
||||
type grpcInsecureDialer interface {
|
||||
@ -515,3 +523,26 @@ func decodeMeasurement(encoded string) ([]byte, error) {
|
||||
}
|
||||
return decoded, nil
|
||||
}
|
||||
|
||||
func unmarshalAttDoc(attDocJSON []byte, attestationVariant variant.Variant) (vtpm.AttestationDocument, error) {
|
||||
attDoc := vtpm.AttestationDocument{
|
||||
Attestation: &attest.Attestation{},
|
||||
}
|
||||
|
||||
// Explicitly initialize this struct, as TeeAttestation
|
||||
// is a "oneof" protobuf field, which needs an explicit
|
||||
// type to be set to be unmarshaled correctly.
|
||||
switch attestationVariant {
|
||||
case variant.AzureTDX{}:
|
||||
attDoc.Attestation.TeeAttestation = &attest.Attestation_TdxAttestation{
|
||||
TdxAttestation: &tdx.QuoteV4{},
|
||||
}
|
||||
default:
|
||||
attDoc.Attestation.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
||||
SevSnpAttestation: &sevsnp.Attestation{},
|
||||
}
|
||||
}
|
||||
|
||||
err := json.Unmarshal(attDocJSON, &attDoc)
|
||||
return attDoc, err
|
||||
}
|
||||
|
@ -208,18 +208,20 @@ func TestVerify(t *testing.T) {
|
||||
|
||||
func TestFormatDefault(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
doc string
|
||||
doc []byte
|
||||
attCfg config.AttestationCfg
|
||||
wantErr bool
|
||||
}{
|
||||
"invalid doc": {
|
||||
doc: "invalid",
|
||||
doc: []byte("invalid"),
|
||||
attCfg: &config.AzureSEVSNP{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, err := formatDefault(context.Background(), tc.doc, nil, logger.NewTest(t))
|
||||
_, err := formatDefault(context.Background(), tc.doc, tc.attCfg, logger.NewTest(t))
|
||||
if tc.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
@ -313,9 +315,9 @@ type stubVerifyClient struct {
|
||||
endpoint string
|
||||
}
|
||||
|
||||
func (c *stubVerifyClient) Verify(_ context.Context, endpoint string, _ *verifyproto.GetAttestationRequest, _ atls.Validator) (string, error) {
|
||||
func (c *stubVerifyClient) Verify(_ context.Context, endpoint string, _ *verifyproto.GetAttestationRequest, _ atls.Validator) ([]byte, error) {
|
||||
c.endpoint = endpoint
|
||||
return "", c.verifyErr
|
||||
return nil, c.verifyErr
|
||||
}
|
||||
|
||||
type stubVerifyAPI struct {
|
||||
|
2
go.mod
2
go.mod
@ -79,7 +79,7 @@ require (
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/google/go-sev-guest v0.11.1
|
||||
github.com/google/go-tdx-guest v0.3.1
|
||||
github.com/google/go-tpm v0.9.1-0.20240510201744-5c2f0887e003
|
||||
github.com/google/go-tpm v0.9.1
|
||||
github.com/google/go-tpm-tools v0.4.4
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/googleapis/gax-go/v2 v2.12.4
|
||||
|
4
go.sum
4
go.sum
@ -420,8 +420,8 @@ github.com/google/go-sev-guest v0.11.1 h1:gnww4U8fHV5DCPz4gykr1s8SEX1fFNcxCBy+vv
|
||||
github.com/google/go-sev-guest v0.11.1/go.mod h1:qBOfb+JmgsUI3aUyzQoGC13Kpp9zwLeWvuyXmA9q77w=
|
||||
github.com/google/go-tdx-guest v0.3.1 h1:gl0KvjdsD4RrJzyLefDOvFOUH3NAJri/3qvaL5m83Iw=
|
||||
github.com/google/go-tdx-guest v0.3.1/go.mod h1:/rc3d7rnPykOPuY8U9saMyEps0PZDThLk/RygXm04nE=
|
||||
github.com/google/go-tpm v0.9.1-0.20240510201744-5c2f0887e003 h1:gfGQAIxsEEAuYuFvjCGpDnTwisMJOz+rUfJMkk4yTmc=
|
||||
github.com/google/go-tpm v0.9.1-0.20240510201744-5c2f0887e003/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM=
|
||||
github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98=
|
||||
github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY=
|
||||
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
||||
|
Loading…
Reference in New Issue
Block a user