2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-03-22 11:03:15 -04:00
|
|
|
package gcp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/rsa"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"testing"
|
|
|
|
|
2022-12-08 05:26:51 -05:00
|
|
|
"cloud.google.com/go/compute/apiv1/computepb"
|
2022-09-21 07:47:57 -04:00
|
|
|
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
2022-03-22 11:03:15 -04:00
|
|
|
"github.com/google/go-tpm-tools/proto/attest"
|
|
|
|
"github.com/googleapis/gax-go/v2"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"google.golang.org/api/option"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
)
|
|
|
|
|
2023-03-06 03:17:08 -05:00
|
|
|
func TestValidateCVM(t *testing.T) {
|
2022-03-22 11:03:15 -04:00
|
|
|
testCases := map[string]struct {
|
2023-03-06 03:17:08 -05:00
|
|
|
state *attest.MachineState
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
2022-03-22 11:03:15 -04:00
|
|
|
}{
|
2023-03-06 03:17:08 -05:00
|
|
|
"is current cvm": {
|
|
|
|
state: &attest.MachineState{Platform: &attest.PlatformState{
|
|
|
|
Firmware: &attest.PlatformState_GceVersion{GceVersion: minimumGceVersion},
|
|
|
|
Technology: attest.GCEConfidentialTechnology_AMD_SEV,
|
|
|
|
}},
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
2023-03-06 03:17:08 -05:00
|
|
|
"is newer cvm": {
|
|
|
|
state: &attest.MachineState{Platform: &attest.PlatformState{
|
|
|
|
Firmware: &attest.PlatformState_GceVersion{GceVersion: minimumGceVersion + 1},
|
|
|
|
Technology: attest.GCEConfidentialTechnology_AMD_SEV,
|
|
|
|
}},
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
2023-03-06 03:17:08 -05:00
|
|
|
"is older cvm": {
|
|
|
|
state: &attest.MachineState{Platform: &attest.PlatformState{
|
|
|
|
Firmware: &attest.PlatformState_GceVersion{GceVersion: minimumGceVersion - 1},
|
|
|
|
Technology: attest.GCEConfidentialTechnology_AMD_SEV,
|
|
|
|
}},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"not a cvm": {
|
2023-03-06 03:17:08 -05:00
|
|
|
state: &attest.MachineState{Platform: &attest.PlatformState{
|
|
|
|
Firmware: &attest.PlatformState_GceVersion{GceVersion: minimumGceVersion},
|
|
|
|
Technology: attest.GCEConfidentialTechnology_NONE,
|
|
|
|
}},
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
2023-03-06 03:17:08 -05:00
|
|
|
err := validateCVM(vtpm.AttestationDocument{}, tc.state)
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-22 11:03:15 -04:00
|
|
|
assert.Error(err)
|
|
|
|
} else {
|
|
|
|
assert.NoError(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrustedKeyFromGCEAPI(t *testing.T) {
|
|
|
|
testPubK := `-----BEGIN PUBLIC KEY-----
|
|
|
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu+OepfHCTiTi27nkTGke
|
|
|
|
dn+AIkiM1AIWWDwqfqG85aNulcj60mGQGXIYV8LoEVkyKOhYBIUmJUaVczB4ltqq
|
|
|
|
ZhR7l46RQw2vnv+XiUmfK555d4ZDInyjTusO69hE6tkuYKdXLlG1HzcrhJ254LE2
|
|
|
|
wXtE1Yf9DygOsWet+S32gmpfH2whUY1mRTdwW4zoY4c3qtmmWImhVVNr6qR8Z95X
|
|
|
|
Y49EteCoNIomQNEZH7EnMlBsh34L7doOsckh1aTvQcrJorQSrBkWKbdV6kvuBKZp
|
|
|
|
fLK0DZiOh9BwZCZANtOqgH3V+AuNk338iON8eKCFRjoiQ40YGM6xKH3E6PHVnuKt
|
|
|
|
uIO0MPvE0qdV8Lvs+nCCrvwP5sJKZuciM40ioEO1pV1y3491xIxYhx3OfN4gg2h8
|
|
|
|
cgdKob/R8qwxqTrfceO36FBFb1vXCUApsm5oy6WxmUtIUgoYhK+6JYpVWDyOJYwP
|
|
|
|
iMJhdJA65n2ZliN8NxEhsaFoMgw76BOiD0wkt/CKPmNbOm5MGS3/fiZCt6A6u3cn
|
|
|
|
Ubhn4tvjy/q5XzVqZtBeoseW2TyyrsAN53LBkSqag5tG/264CQDigQ6Y/OADOE2x
|
|
|
|
n08MyrFHIL/wFMscOvJo7c2Eo4EW1yXkEkAy5tF5PZgnfRObakj4gdqPeq18FNzc
|
|
|
|
Y+t5OxL3kL15VzY1Ob0d5cMCAwEAAQ==
|
|
|
|
-----END PUBLIC KEY-----`
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
instanceInfo []byte
|
|
|
|
getClient func(ctx context.Context, opts ...option.ClientOption) (gcpRestClient, error)
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr bool
|
2022-03-22 11:03:15 -04:00
|
|
|
}{
|
|
|
|
"success": {
|
2023-06-16 03:40:08 -04:00
|
|
|
instanceInfo: mustMarshal(&attest.GCEInstanceInfo{}, require.New(t)),
|
2022-03-22 11:03:15 -04:00
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{
|
|
|
|
SigningKey: &computepb.ShieldedInstanceIdentityEntry{
|
|
|
|
EkPub: proto.String(testPubK),
|
|
|
|
},
|
|
|
|
}, nil, nil),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: false,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"Unmarshal error": {
|
|
|
|
instanceInfo: []byte("error"),
|
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{
|
|
|
|
SigningKey: &computepb.ShieldedInstanceIdentityEntry{
|
|
|
|
EkPub: proto.String(testPubK),
|
|
|
|
},
|
|
|
|
}, nil, nil),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"empty signing key": {
|
2023-06-16 03:40:08 -04:00
|
|
|
instanceInfo: mustMarshal(&attest.GCEInstanceInfo{}, require.New(t)),
|
2022-03-22 11:03:15 -04:00
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{}, nil, nil),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"new client error": {
|
2023-06-16 03:40:08 -04:00
|
|
|
instanceInfo: mustMarshal(&attest.GCEInstanceInfo{}, require.New(t)),
|
2022-03-22 11:03:15 -04:00
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{
|
|
|
|
SigningKey: &computepb.ShieldedInstanceIdentityEntry{
|
|
|
|
EkPub: proto.String(testPubK),
|
|
|
|
},
|
|
|
|
}, errors.New("error"), nil),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"GetShieldedInstanceIdentity error": {
|
2023-06-16 03:40:08 -04:00
|
|
|
instanceInfo: mustMarshal(&attest.GCEInstanceInfo{}, require.New(t)),
|
2022-03-22 11:03:15 -04:00
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{
|
|
|
|
SigningKey: &computepb.ShieldedInstanceIdentityEntry{
|
|
|
|
EkPub: proto.String(testPubK),
|
|
|
|
},
|
|
|
|
}, nil, errors.New("error")),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
"Decode error": {
|
2023-06-16 03:40:08 -04:00
|
|
|
instanceInfo: mustMarshal(&attest.GCEInstanceInfo{}, require.New(t)),
|
2022-03-22 11:03:15 -04:00
|
|
|
getClient: prepareFakeClient(&computepb.ShieldedInstanceIdentity{
|
|
|
|
SigningKey: &computepb.ShieldedInstanceIdentityEntry{
|
|
|
|
EkPub: proto.String("Not a public key"),
|
|
|
|
},
|
|
|
|
}, nil, nil),
|
2022-04-26 10:54:05 -04:00
|
|
|
wantErr: true,
|
2022-03-22 11:03:15 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
|
2023-03-21 07:46:49 -04:00
|
|
|
v := &Validator{
|
|
|
|
restClient: tc.getClient,
|
|
|
|
}
|
|
|
|
attDoc := vtpm.AttestationDocument{InstanceInfo: tc.instanceInfo}
|
|
|
|
|
|
|
|
out, err := v.trustedKeyFromGCEAPI(context.Background(), attDoc, nil)
|
2022-03-22 11:03:15 -04:00
|
|
|
|
2022-04-26 10:54:05 -04:00
|
|
|
if tc.wantErr {
|
2022-03-22 11:03:15 -04:00
|
|
|
assert.Error(err)
|
|
|
|
} else {
|
|
|
|
assert.NoError(err)
|
|
|
|
_, ok := out.(*rsa.PublicKey)
|
|
|
|
assert.True(ok)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-16 03:40:08 -04:00
|
|
|
func mustMarshal(in *attest.GCEInstanceInfo, require *require.Assertions) []byte {
|
2022-03-22 11:03:15 -04:00
|
|
|
out, err := json.Marshal(in)
|
|
|
|
require.NoError(err)
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakeInstanceClient struct {
|
|
|
|
getIdentErr error
|
|
|
|
ident *computepb.ShieldedInstanceIdentity
|
|
|
|
}
|
|
|
|
|
|
|
|
func prepareFakeClient(ident *computepb.ShieldedInstanceIdentity, newErr, getIdentErr error) func(ctx context.Context, opts ...option.ClientOption) (gcpRestClient, error) {
|
|
|
|
return func(ctx context.Context, opts ...option.ClientOption) (gcpRestClient, error) {
|
|
|
|
return &fakeInstanceClient{
|
|
|
|
getIdentErr: getIdentErr,
|
|
|
|
ident: ident,
|
|
|
|
}, newErr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *fakeInstanceClient) Close() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-03-20 06:03:36 -04:00
|
|
|
func (c *fakeInstanceClient) GetShieldedInstanceIdentity(_ context.Context, _ *computepb.GetShieldedInstanceIdentityInstanceRequest, _ ...gax.CallOption) (*computepb.ShieldedInstanceIdentity, error) {
|
2022-03-22 11:03:15 -04:00
|
|
|
return c.ident, c.getIdentErr
|
|
|
|
}
|