mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
COCOS-395 - Cloud Provider Firmware Integration (#415)
* add CC platform identification capability * add token verification * add snp azure * add azure snp report verification * fix linter errors * fix agent tests * expand the CC provider * fix azure atls * rebase branch * add nonce check for azure token * rename package attestations * remove alias attestations --------- Co-authored-by: Ubuntu <azureuser@UVCTestCVM.bu0p0zdolasezg1jifpyqhaxuc.dx.internal.cloudapp.net>
This commit is contained in:
committed by
GitHub
parent
5c60bc2a48
commit
3102114ff3
@@ -36,7 +36,7 @@ jobs:
|
|||||||
mkdir coverage
|
mkdir coverage
|
||||||
|
|
||||||
- name: Run Agent tests
|
- name: Run Agent tests
|
||||||
run: go test --tags embed -v --race -covermode=atomic -coverprofile coverage/agent.out ./agent/...
|
run: go test -v --race -covermode=atomic -coverprofile coverage/agent.out ./agent/...
|
||||||
|
|
||||||
- name: Run cli tests
|
- name: Run cli tests
|
||||||
run: go test -v --race -covermode=atomic -coverprofile coverage/cli.out ./cli/...
|
run: go test -v --race -covermode=atomic -coverprofile coverage/cli.out ./cli/...
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-kit/kit/endpoint"
|
"github.com/go-kit/kit/endpoint"
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func algoEndpoint(svc agent.Service) endpoint.Endpoint {
|
func algoEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||||
@@ -71,7 +71,7 @@ func attestationEndpoint(svc agent.Service) endpoint.Endpoint {
|
|||||||
if err := req.validate(); err != nil {
|
if err := req.validate(); err != nil {
|
||||||
return attestationRes{}, err
|
return attestationRes{}, err
|
||||||
}
|
}
|
||||||
file, err := svc.Attestation(ctx, req.TeeNonce, req.VtpmNonce, config.AttestationType(req.AttType))
|
file, err := svc.Attestation(ctx, req.TeeNonce, req.VtpmNonce, attestation.PlatformType(req.AttType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return attestationRes{}, err
|
return attestationRes{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
"github.com/ultravioletrs/cocos/agent/mocks"
|
"github.com/ultravioletrs/cocos/agent/mocks"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -142,11 +142,11 @@ func TestAttestationEndpoint(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Success",
|
name: "Success",
|
||||||
req: attestationReq{TeeNonce: sha3.Sum512([]byte("report data")), VtpmNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: config.SNP},
|
req: attestationReq{TeeNonce: sha3.Sum512([]byte("report data")), VtpmNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: attestation.SNP},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Service Error",
|
name: "Service Error",
|
||||||
req: attestationReq{TeeNonce: sha3.Sum512([]byte("report data")), VtpmNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: config.SNP},
|
req: attestationReq{TeeNonce: sha3.Sum512([]byte("report data")), VtpmNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: attestation.SNP},
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package grpc
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
)
|
)
|
||||||
@@ -44,12 +44,12 @@ func (req resultReq) validate() error {
|
|||||||
type attestationReq struct {
|
type attestationReq struct {
|
||||||
TeeNonce [quoteprovider.Nonce]byte
|
TeeNonce [quoteprovider.Nonce]byte
|
||||||
VtpmNonce [vtpm.Nonce]byte
|
VtpmNonce [vtpm.Nonce]byte
|
||||||
AttType config.AttestationType
|
AttType attestation.PlatformType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req attestationReq) validate() error {
|
func (req attestationReq) validate() error {
|
||||||
switch req.AttType {
|
switch req.AttType {
|
||||||
case config.SNP, config.VTPM, config.SNPvTPM:
|
case attestation.SNP, attestation.VTPM, attestation.SNPvTPM:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return errors.New("invalid attestation type in attestation request")
|
return errors.New("invalid attestation type in attestation request")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-kit/kit/transport/grpc"
|
"github.com/go-kit/kit/transport/grpc"
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -124,7 +124,7 @@ func decodeAttestationRequest(_ context.Context, grpcReq interface{}) (interface
|
|||||||
|
|
||||||
copy(reportData[:], req.TeeNonce)
|
copy(reportData[:], req.TeeNonce)
|
||||||
copy(nonce[:], req.VtpmNonce)
|
copy(nonce[:], req.VtpmNonce)
|
||||||
return attestationReq{TeeNonce: reportData, VtpmNonce: nonce, AttType: config.AttestationType(req.Type)}, nil
|
return attestationReq{TeeNonce: reportData, VtpmNonce: nonce, AttType: attestation.PlatformType(req.Type)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeAttestationResponse(_ context.Context, response interface{}) (interface{}, error) {
|
func encodeAttestationResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
"github.com/ultravioletrs/cocos/agent/mocks"
|
"github.com/ultravioletrs/cocos/agent/mocks"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -156,7 +156,7 @@ func TestAttestation(t *testing.T) {
|
|||||||
|
|
||||||
reportData := [quoteprovider.Nonce]byte{}
|
reportData := [quoteprovider.Nonce]byte{}
|
||||||
vtpmNonce := [vtpm.Nonce]byte{}
|
vtpmNonce := [vtpm.Nonce]byte{}
|
||||||
attestationType := config.SNP
|
attestationType := attestation.SNP
|
||||||
mockService.On("Attestation", mock.Anything, reportData, vtpmNonce, attestationType).Return([]byte("attestation data"), nil)
|
mockService.On("Attestation", mock.Anything, reportData, vtpmNonce, attestationType).Return([]byte("attestation data"), nil)
|
||||||
|
|
||||||
err := server.Attestation(&agent.AttestationRequest{TeeNonce: reportData[:]}, mockStream)
|
err := server.Attestation(&agent.AttestationRequest{TeeNonce: reportData[:]}, mockStream)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
)
|
)
|
||||||
@@ -106,7 +106,7 @@ func (lm *loggingMiddleware) Result(ctx context.Context) (response []byte, err e
|
|||||||
return lm.svc.Result(ctx)
|
return lm.svc.Result(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lm *loggingMiddleware) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType config.AttestationType) (response []byte, err error) {
|
func (lm *loggingMiddleware) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) (response []byte, err error) {
|
||||||
defer func(begin time.Time) {
|
defer func(begin time.Time) {
|
||||||
message := fmt.Sprintf("Method Attestation took %s to complete", time.Since(begin))
|
message := fmt.Sprintf("Method Attestation took %s to complete", time.Since(begin))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-kit/kit/metrics"
|
"github.com/go-kit/kit/metrics"
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
)
|
)
|
||||||
@@ -92,7 +92,7 @@ func (ms *metricsMiddleware) Result(ctx context.Context) ([]byte, error) {
|
|||||||
return ms.svc.Result(ctx)
|
return ms.svc.Result(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType config.AttestationType) ([]byte, error) {
|
func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error) {
|
||||||
defer func(begin time.Time) {
|
defer func(begin time.Time) {
|
||||||
ms.counter.With("method", "attestation").Add(1)
|
ms.counter.With("method", "attestation").Add(1)
|
||||||
ms.latency.With("method", "attestation").Observe(time.Since(begin).Seconds())
|
ms.latency.With("method", "attestation").Observe(time.Since(begin).Seconds())
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/google/go-sev-guest/client"
|
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||||
"github.com/ultravioletrs/cocos/agent/auth"
|
"github.com/ultravioletrs/cocos/agent/auth"
|
||||||
@@ -33,17 +32,15 @@ type agentServer struct {
|
|||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
svc agent.Service
|
svc agent.Service
|
||||||
host string
|
host string
|
||||||
qp client.LeveledQuoteProvider
|
|
||||||
caUrl string
|
caUrl string
|
||||||
cvmId string
|
cvmId string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(logger *slog.Logger, svc agent.Service, host string, qp client.LeveledQuoteProvider, caUrl string, cvmId string) AgentServer {
|
func NewServer(logger *slog.Logger, svc agent.Service, host string, caUrl string, cvmId string) AgentServer {
|
||||||
return &agentServer{
|
return &agentServer{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
svc: svc,
|
svc: svc,
|
||||||
host: host,
|
host: host,
|
||||||
qp: qp,
|
|
||||||
caUrl: caUrl,
|
caUrl: caUrl,
|
||||||
cvmId: cvmId,
|
cvmId: cvmId,
|
||||||
}
|
}
|
||||||
@@ -81,7 +78,7 @@ func (as *agentServer) Start(cfg agent.AgentConfig, cmp agent.Computation) error
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
as.gs = grpcserver.New(ctx, cancel, svcName, agentGrpcServerConfig, registerAgentServiceServer, as.logger, as.qp, authSvc, as.caUrl, as.cvmId)
|
as.gs = grpcserver.New(ctx, cancel, svcName, agentGrpcServerConfig, registerAgentServiceServer, as.logger, authSvc, as.caUrl, as.cvmId)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := as.gs.Start()
|
err := as.gs.Start()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package mocks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
agent "github.com/ultravioletrs/cocos/agent"
|
agent "github.com/ultravioletrs/cocos/agent"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
attestation "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func (_c *Service_Algo_Call) RunAndReturn(run func(context.Context, agent.Algori
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attestation provides a mock function with given fields: ctx, reportData, nonce, attType
|
// Attestation provides a mock function with given fields: ctx, reportData, nonce, attType
|
||||||
func (_m *Service) Attestation(ctx context.Context, reportData [64]byte, nonce [32]byte, attType config.AttestationType) ([]byte, error) {
|
func (_m *Service) Attestation(ctx context.Context, reportData [64]byte, nonce [32]byte, attType attestation.PlatformType) ([]byte, error) {
|
||||||
ret := _m.Called(ctx, reportData, nonce, attType)
|
ret := _m.Called(ctx, reportData, nonce, attType)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
@@ -84,10 +84,10 @@ func (_m *Service) Attestation(ctx context.Context, reportData [64]byte, nonce [
|
|||||||
|
|
||||||
var r0 []byte
|
var r0 []byte
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, [64]byte, [32]byte, config.AttestationType) ([]byte, error)); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, [64]byte, [32]byte, attestation.PlatformType) ([]byte, error)); ok {
|
||||||
return rf(ctx, reportData, nonce, attType)
|
return rf(ctx, reportData, nonce, attType)
|
||||||
}
|
}
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, [64]byte, [32]byte, config.AttestationType) []byte); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, [64]byte, [32]byte, attestation.PlatformType) []byte); ok {
|
||||||
r0 = rf(ctx, reportData, nonce, attType)
|
r0 = rf(ctx, reportData, nonce, attType)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
@@ -95,7 +95,7 @@ func (_m *Service) Attestation(ctx context.Context, reportData [64]byte, nonce [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, [64]byte, [32]byte, config.AttestationType) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, [64]byte, [32]byte, attestation.PlatformType) error); ok {
|
||||||
r1 = rf(ctx, reportData, nonce, attType)
|
r1 = rf(ctx, reportData, nonce, attType)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
@@ -113,14 +113,14 @@ type Service_Attestation_Call struct {
|
|||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - reportData [64]byte
|
// - reportData [64]byte
|
||||||
// - nonce [32]byte
|
// - nonce [32]byte
|
||||||
// - attType config.AttestationType
|
// - attType attestation.PlatformType
|
||||||
func (_e *Service_Expecter) Attestation(ctx interface{}, reportData interface{}, nonce interface{}, attType interface{}) *Service_Attestation_Call {
|
func (_e *Service_Expecter) Attestation(ctx interface{}, reportData interface{}, nonce interface{}, attType interface{}) *Service_Attestation_Call {
|
||||||
return &Service_Attestation_Call{Call: _e.mock.On("Attestation", ctx, reportData, nonce, attType)}
|
return &Service_Attestation_Call{Call: _e.mock.On("Attestation", ctx, reportData, nonce, attType)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Service_Attestation_Call) Run(run func(ctx context.Context, reportData [64]byte, nonce [32]byte, attType config.AttestationType)) *Service_Attestation_Call {
|
func (_c *Service_Attestation_Call) Run(run func(ctx context.Context, reportData [64]byte, nonce [32]byte, attType attestation.PlatformType)) *Service_Attestation_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
run(args[0].(context.Context), args[1].([64]byte), args[2].([32]byte), args[3].(config.AttestationType))
|
run(args[0].(context.Context), args[1].([64]byte), args[2].([32]byte), args[3].(attestation.PlatformType))
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ func (_c *Service_Attestation_Call) Return(_a0 []byte, _a1 error) *Service_Attes
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *Service_Attestation_Call) RunAndReturn(run func(context.Context, [64]byte, [32]byte, config.AttestationType) ([]byte, error)) *Service_Attestation_Call {
|
func (_c *Service_Attestation_Call) RunAndReturn(run func(context.Context, [64]byte, [32]byte, attestation.PlatformType) ([]byte, error)) *Service_Attestation_Call {
|
||||||
_c.Call.Return(run)
|
_c.Call.Return(run)
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-34
@@ -6,7 +6,6 @@ package agent
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
@@ -14,7 +13,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
|
|
||||||
"github.com/google/go-sev-guest/client"
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
"github.com/ultravioletrs/cocos/agent/algorithm"
|
"github.com/ultravioletrs/cocos/agent/algorithm"
|
||||||
"github.com/ultravioletrs/cocos/agent/algorithm/binary"
|
"github.com/ultravioletrs/cocos/agent/algorithm/binary"
|
||||||
"github.com/ultravioletrs/cocos/agent/algorithm/docker"
|
"github.com/ultravioletrs/cocos/agent/algorithm/docker"
|
||||||
@@ -23,7 +22,7 @@ import (
|
|||||||
"github.com/ultravioletrs/cocos/agent/events"
|
"github.com/ultravioletrs/cocos/agent/events"
|
||||||
"github.com/ultravioletrs/cocos/agent/statemachine"
|
"github.com/ultravioletrs/cocos/agent/statemachine"
|
||||||
"github.com/ultravioletrs/cocos/internal"
|
"github.com/ultravioletrs/cocos/internal"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
@@ -105,6 +104,8 @@ var (
|
|||||||
ErrAllResultsConsumed = errors.New("all results have been consumed by declared consumers")
|
ErrAllResultsConsumed = errors.New("all results have been consumed by declared consumers")
|
||||||
// ErrAttestationFailed attestation failed.
|
// ErrAttestationFailed attestation failed.
|
||||||
ErrAttestationFailed = errors.New("failed to get raw quote")
|
ErrAttestationFailed = errors.New("failed to get raw quote")
|
||||||
|
// ErrAttestationVTpmFailed vTPM attestation failed.
|
||||||
|
ErrAttestationVTpmFailed = errors.New("failed to get vTPM quote")
|
||||||
// ErrAttType indicates that the attestation type that is requested does not exist or is not supported.
|
// ErrAttType indicates that the attestation type that is requested does not exist or is not supported.
|
||||||
ErrAttestationType = errors.New("attestation type does not exist or is not supported")
|
ErrAttestationType = errors.New("attestation type does not exist or is not supported")
|
||||||
)
|
)
|
||||||
@@ -117,41 +118,39 @@ type Service interface {
|
|||||||
Algo(ctx context.Context, algorithm Algorithm) error
|
Algo(ctx context.Context, algorithm Algorithm) error
|
||||||
Data(ctx context.Context, dataset Dataset) error
|
Data(ctx context.Context, dataset Dataset) error
|
||||||
Result(ctx context.Context) ([]byte, error)
|
Result(ctx context.Context) ([]byte, error)
|
||||||
Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType config.AttestationType) ([]byte, error)
|
Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error)
|
||||||
IMAMeasurements(ctx context.Context) ([]byte, []byte, error)
|
IMAMeasurements(ctx context.Context) ([]byte, []byte, error)
|
||||||
State() string
|
State() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type agentService struct {
|
type agentService struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
computation Computation // Holds the current computation request details.
|
computation Computation // Holds the current computation request details.
|
||||||
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
|
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
|
||||||
result []byte // Stores the result of the computation.
|
result []byte // Stores the result of the computation.
|
||||||
sm statemachine.StateMachine // Manages the state transitions of the agent service.
|
sm statemachine.StateMachine // Manages the state transitions of the agent service.
|
||||||
runError error // Stores any error encountered during the computation run.
|
runError error // Stores any error encountered during the computation run.
|
||||||
eventSvc events.Service // Service for publishing events related to computation.
|
eventSvc events.Service // Service for publishing events related to computation.
|
||||||
quoteProvider client.LeveledQuoteProvider // Provider for generating attestation quotes.
|
provider attestation.Provider // Provider for generating attestation quotes.
|
||||||
logger *slog.Logger // Logger for the agent service.
|
logger *slog.Logger // Logger for the agent service.
|
||||||
resultsConsumed bool // Indicates if the results have been consumed.
|
resultsConsumed bool // Indicates if the results have been consumed.
|
||||||
cancel context.CancelFunc // Cancels the computation context.
|
cancel context.CancelFunc // Cancels the computation context.
|
||||||
vmpl int // VMPL at which the Agent is running.
|
vmpl int // VMPL at which the Agent is running.
|
||||||
vtpmAttest vtpm.VtpmAttest // Attestation function.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Service = (*agentService)(nil)
|
var _ Service = (*agentService)(nil)
|
||||||
|
|
||||||
// New instantiates the agent service implementation.
|
// New instantiates the agent service implementation.
|
||||||
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, quoteProvider client.LeveledQuoteProvider, vmlp int, vtpmAttest vtpm.VtpmAttest) Service {
|
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, provider attestation.Provider, vmlp int) Service {
|
||||||
sm := statemachine.NewStateMachine(Idle)
|
sm := statemachine.NewStateMachine(Idle)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
svc := &agentService{
|
svc := &agentService{
|
||||||
sm: sm,
|
sm: sm,
|
||||||
eventSvc: eventSvc,
|
eventSvc: eventSvc,
|
||||||
quoteProvider: quoteProvider,
|
provider: provider,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
vmpl: vmlp,
|
vmpl: vmlp,
|
||||||
vtpmAttest: vtpmAttest,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transitions := []statemachine.Transition{
|
transitions := []statemachine.Transition{
|
||||||
@@ -423,24 +422,24 @@ func (as *agentService) Result(ctx context.Context) ([]byte, error) {
|
|||||||
return as.result, as.runError
|
return as.result, as.runError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (as *agentService) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType config.AttestationType) ([]byte, error) {
|
func (as *agentService) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error) {
|
||||||
switch attType {
|
switch attType {
|
||||||
case config.SNP:
|
case attestation.SNP:
|
||||||
rawQuote, err := as.quoteProvider.GetRawQuoteAtLevel(reportData, uint(as.vmpl))
|
rawQuote, err := as.provider.TeeAttestation(reportData[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, errors.Wrap(ErrAttestationFailed, err)
|
||||||
}
|
}
|
||||||
return rawQuote, nil
|
return rawQuote, nil
|
||||||
case config.VTPM:
|
case attestation.VTPM:
|
||||||
vTPMQuote, err := as.vtpmAttest(reportData[:], nonce[:], false)
|
vTPMQuote, err := as.provider.VTpmAttestation(nonce[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, errors.Wrap(ErrAttestationVTpmFailed, err)
|
||||||
}
|
}
|
||||||
return vTPMQuote, nil
|
return vTPMQuote, nil
|
||||||
case config.SNPvTPM:
|
case attestation.SNPvTPM:
|
||||||
vTPMQuote, err := as.vtpmAttest(reportData[:], nonce[:], true)
|
vTPMQuote, err := as.provider.Attestation(reportData[:], nonce[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, errors.Wrap(ErrAttestationVTpmFailed, err)
|
||||||
}
|
}
|
||||||
return vTPMQuote, nil
|
return vTPMQuote, nil
|
||||||
default:
|
default:
|
||||||
|
|||||||
+50
-23
@@ -20,8 +20,9 @@ import (
|
|||||||
"github.com/ultravioletrs/cocos/agent/events/mocks"
|
"github.com/ultravioletrs/cocos/agent/events/mocks"
|
||||||
"github.com/ultravioletrs/cocos/agent/statemachine"
|
"github.com/ultravioletrs/cocos/agent/statemachine"
|
||||||
smmocks "github.com/ultravioletrs/cocos/agent/statemachine/mocks"
|
smmocks "github.com/ultravioletrs/cocos/agent/statemachine/mocks"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
mocks2 "github.com/ultravioletrs/cocos/pkg/attestation/mocks"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
mocks2 "github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider/mocks"
|
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
@@ -36,9 +37,6 @@ var (
|
|||||||
const datasetFile = "iris.csv"
|
const datasetFile = "iris.csv"
|
||||||
|
|
||||||
func TestAlgo(t *testing.T) {
|
func TestAlgo(t *testing.T) {
|
||||||
qp, err := quoteprovider.GetLeveledQuoteProvider()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
algo, err := os.ReadFile(algoPath)
|
algo, err := os.ReadFile(algoPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -121,7 +119,7 @@ func TestAlgo(t *testing.T) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
svc := New(ctx, mglog.NewMock(), events, qp, 0, vtpm.EmptyAttest)
|
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
|
||||||
|
|
||||||
err := svc.InitComputation(ctx, testComputation(t))
|
err := svc.InitComputation(ctx, testComputation(t))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -140,9 +138,6 @@ func TestAlgo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestData(t *testing.T) {
|
func TestData(t *testing.T) {
|
||||||
qp, err := quoteprovider.GetLeveledQuoteProvider()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
algo, err := os.ReadFile(algoPath)
|
algo, err := os.ReadFile(algoPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -216,7 +211,7 @@ func TestData(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
svc := New(ctx, mglog.NewMock(), events, qp, 0, vtpm.EmptyAttest)
|
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
|
||||||
|
|
||||||
err := svc.InitComputation(ctx, testComputation(t))
|
err := svc.InitComputation(ctx, testComputation(t))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -241,9 +236,6 @@ func TestData(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResult(t *testing.T) {
|
func TestResult(t *testing.T) {
|
||||||
qp, err := quoteprovider.GetLeveledQuoteProvider()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
err error
|
err error
|
||||||
@@ -301,10 +293,10 @@ func TestResult(t *testing.T) {
|
|||||||
sm.On("SendEvent", mock.Anything).Return()
|
sm.On("SendEvent", mock.Anything).Return()
|
||||||
|
|
||||||
svc := &agentService{
|
svc := &agentService{
|
||||||
sm: sm,
|
sm: sm,
|
||||||
eventSvc: events,
|
eventSvc: events,
|
||||||
quoteProvider: qp,
|
provider: &attestation.EmptyProvider{},
|
||||||
computation: testComputation(t),
|
computation: testComputation(t),
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -324,29 +316,64 @@ func TestResult(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAttestation(t *testing.T) {
|
func TestAttestation(t *testing.T) {
|
||||||
qp := new(mocks2.LeveledQuoteProvider)
|
provider := new(mocks2.Provider)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
reportData [quoteprovider.Nonce]byte
|
reportData [quoteprovider.Nonce]byte
|
||||||
nonce [vtpm.Nonce]byte
|
nonce [vtpm.Nonce]byte
|
||||||
rawQuote []uint8
|
rawQuote []uint8
|
||||||
|
platform attestation.PlatformType
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Test attestation successful",
|
name: "Test SNP attestation successful",
|
||||||
reportData: generateReportData(),
|
reportData: generateReportData(),
|
||||||
nonce: [32]byte{},
|
nonce: [32]byte{},
|
||||||
rawQuote: make([]uint8, 0),
|
rawQuote: make([]uint8, 0),
|
||||||
|
platform: attestation.SNP,
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Test attestation failed",
|
name: "Test SNP attestation failed",
|
||||||
reportData: generateReportData(),
|
reportData: generateReportData(),
|
||||||
nonce: [32]byte{},
|
nonce: [32]byte{},
|
||||||
rawQuote: nil,
|
rawQuote: nil,
|
||||||
|
platform: attestation.SNP,
|
||||||
err: ErrAttestationFailed,
|
err: ErrAttestationFailed,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Test vTPM attestation successful",
|
||||||
|
reportData: generateReportData(),
|
||||||
|
nonce: [32]byte{},
|
||||||
|
rawQuote: make([]uint8, 0),
|
||||||
|
platform: attestation.VTPM,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test vTPM attestation failed",
|
||||||
|
reportData: generateReportData(),
|
||||||
|
nonce: [32]byte{},
|
||||||
|
rawQuote: nil,
|
||||||
|
platform: attestation.VTPM,
|
||||||
|
err: ErrAttestationVTpmFailed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test SNP-vTPM attestation successful",
|
||||||
|
reportData: generateReportData(),
|
||||||
|
nonce: [32]byte{},
|
||||||
|
rawQuote: make([]uint8, 0),
|
||||||
|
platform: attestation.SNPvTPM,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test SNP-vTPM attestation failed",
|
||||||
|
reportData: generateReportData(),
|
||||||
|
nonce: [32]byte{},
|
||||||
|
rawQuote: nil,
|
||||||
|
platform: attestation.SNPvTPM,
|
||||||
|
err: ErrAttestationVTpmFailed,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@@ -359,13 +386,13 @@ func TestAttestation(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
getQuote := qp.On("GetRawQuoteAtLevel", mock.Anything, mock.Anything).Return(tc.rawQuote, tc.err)
|
getQuote := provider.On("TeeAttestation", mock.Anything).Return(tc.rawQuote, tc.err)
|
||||||
if tc.err != ErrAttestationFailed {
|
if tc.err != ErrAttestationFailed && tc.err != ErrAttestationVTpmFailed {
|
||||||
getQuote = qp.On("GetRawQuoteAtLevel", mock.Anything, mock.Anything).Return(tc.nonce, nil)
|
getQuote = provider.On("TeeAttestation", mock.Anything).Return(tc.nonce, nil)
|
||||||
}
|
}
|
||||||
defer getQuote.Unset()
|
defer getQuote.Unset()
|
||||||
|
|
||||||
svc := New(ctx, mglog.NewMock(), events, qp, 0, vtpm.EmptyAttest)
|
svc := New(ctx, mglog.NewMock(), events, provider, 0)
|
||||||
time.Sleep(300 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
_, err := svc.Attestation(ctx, tc.reportData, tc.nonce, 0)
|
_, err := svc.Attestation(ctx, tc.reportData, tc.nonce, 0)
|
||||||
assert.True(t, errors.Contains(err, tc.err), "expected %v, got %v", tc.err, err)
|
assert.True(t, errors.Contains(err, tc.err), "expected %v, got %v", tc.err, err)
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
// Copyright (c) Ultraviolet
|
// Copyright (c) Ultraviolet
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
//go:build embed
|
|
||||||
// +build embed
|
|
||||||
|
|
||||||
package cocosai
|
package cocosai
|
||||||
|
|
||||||
import _ "embed"
|
import _ "embed"
|
||||||
|
|||||||
+93
-107
@@ -3,7 +3,6 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -20,11 +19,10 @@ import (
|
|||||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||||
"github.com/google/go-sev-guest/tools/lib/report"
|
"github.com/google/go-sev-guest/tools/lib/report"
|
||||||
tpmAttest "github.com/google/go-tpm-tools/proto/attest"
|
tpmAttest "github.com/google/go-tpm-tools/proto/attest"
|
||||||
"github.com/google/go-tpm-tools/server"
|
|
||||||
"github.com/google/go-tpm/legacy/tpm2"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation/azure"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
@@ -112,6 +110,9 @@ const (
|
|||||||
SNP = "snp"
|
SNP = "snp"
|
||||||
VTPM = "vtpm"
|
VTPM = "vtpm"
|
||||||
SNPvTPM = "snp-vtpm"
|
SNPvTPM = "snp-vtpm"
|
||||||
|
CCNone = "none"
|
||||||
|
CCAzure = "azure"
|
||||||
|
CCGCP = "gcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -128,7 +129,7 @@ var (
|
|||||||
trustedIdKeyHashes []string
|
trustedIdKeyHashes []string
|
||||||
attestationFile string
|
attestationFile string
|
||||||
tpmAttestationFile string
|
tpmAttestationFile string
|
||||||
attestation []byte
|
attestationRaw []byte
|
||||||
empty16 = [size16]byte{}
|
empty16 = [size16]byte{}
|
||||||
empty32 = [size32]byte{}
|
empty32 = [size32]byte{}
|
||||||
empty64 = [size64]byte{}
|
empty64 = [size64]byte{}
|
||||||
@@ -140,16 +141,11 @@ var (
|
|||||||
format string
|
format string
|
||||||
teeNonce []byte
|
teeNonce []byte
|
||||||
getTextProtoAttestation bool
|
getTextProtoAttestation bool
|
||||||
|
cloud string
|
||||||
)
|
)
|
||||||
|
|
||||||
var errEmptyFile = errors.New("input file is empty")
|
var errEmptyFile = errors.New("input file is empty")
|
||||||
|
|
||||||
var marshalOptions = prototext.MarshalOptions{
|
|
||||||
Multiline: true,
|
|
||||||
EmitASCII: true,
|
|
||||||
}
|
|
||||||
var unmarshalOptions = prototext.UnmarshalOptions{}
|
|
||||||
|
|
||||||
func (cli *CLI) NewAttestationCmd() *cobra.Command {
|
func (cli *CLI) NewAttestationCmd() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "attestation [command]",
|
Use: "attestation [command]",
|
||||||
@@ -203,32 +199,32 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
|
|||||||
|
|
||||||
attestationType := args[0]
|
attestationType := args[0]
|
||||||
|
|
||||||
attType := config.SNP
|
attType := attestation.SNP
|
||||||
switch attestationType {
|
switch attestationType {
|
||||||
case SNP:
|
case SNP:
|
||||||
cmd.Println("Fetching SEV-SNP attestation report")
|
cmd.Println("Fetching SEV-SNP attestation report")
|
||||||
case VTPM:
|
case VTPM:
|
||||||
cmd.Println("Fetching vTPM report")
|
cmd.Println("Fetching vTPM report")
|
||||||
attType = config.VTPM
|
attType = attestation.VTPM
|
||||||
case SNPvTPM:
|
case SNPvTPM:
|
||||||
cmd.Println("Fetching SEV-SNP and vTPM report")
|
cmd.Println("Fetching SEV-SNP and vTPM report")
|
||||||
attType = config.SNPvTPM
|
attType = attestation.SNPvTPM
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attType == config.VTPM || attType == config.SNPvTPM) && len(nonce) == 0 {
|
if (attType == attestation.VTPM || attType == attestation.SNPvTPM) && len(nonce) == 0 {
|
||||||
msg := color.New(color.FgRed).Sprint("vTPM nonce must be defined for vTPM attestation ❌ ")
|
msg := color.New(color.FgRed).Sprint("vTPM nonce must be defined for vTPM attestation ❌ ")
|
||||||
cmd.Println(msg)
|
cmd.Println(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attType == config.SNP || attType == config.SNPvTPM) && len(teeNonce) == 0 {
|
if (attType == attestation.SNP || attType == attestation.SNPvTPM) && len(teeNonce) == 0 {
|
||||||
msg := color.New(color.FgRed).Sprint("TEE nonce must be defined for SEV-SNP attestation ❌ ")
|
msg := color.New(color.FgRed).Sprint("TEE nonce must be defined for SEV-SNP attestation ❌ ")
|
||||||
cmd.Println(msg)
|
cmd.Println(msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var fixedReportData [quoteprovider.Nonce]byte
|
var fixedReportData [quoteprovider.Nonce]byte
|
||||||
if attType != config.VTPM {
|
if attType != attestation.VTPM {
|
||||||
if len(teeNonce) > quoteprovider.Nonce {
|
if len(teeNonce) > quoteprovider.Nonce {
|
||||||
msg := color.New(color.FgRed).Sprintf("nonce must be a hex encoded string of length lesser or equal %d bytes ❌ ", quoteprovider.Nonce)
|
msg := color.New(color.FgRed).Sprintf("nonce must be a hex encoded string of length lesser or equal %d bytes ❌ ", quoteprovider.Nonce)
|
||||||
cmd.Println(msg)
|
cmd.Println(msg)
|
||||||
@@ -239,7 +235,7 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fixedVtpmNonceByte [vtpm.Nonce]byte
|
var fixedVtpmNonceByte [vtpm.Nonce]byte
|
||||||
if attType != config.SNP {
|
if attType != attestation.SNP {
|
||||||
if len(nonce) > vtpm.Nonce {
|
if len(nonce) > vtpm.Nonce {
|
||||||
msg := color.New(color.FgRed).Sprintf("vTPM nonce must be a hex encoded string of length lesser or equal %d bytes ❌ ", vtpm.Nonce)
|
msg := color.New(color.FgRed).Sprintf("vTPM nonce must be a hex encoded string of length lesser or equal %d bytes ❌ ", vtpm.Nonce)
|
||||||
cmd.Println(msg)
|
cmd.Println(msg)
|
||||||
@@ -344,13 +340,15 @@ func isFileJSON(filename string) bool {
|
|||||||
func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "validate",
|
Use: "validate",
|
||||||
Short: "Validate and verify attestation information. You can choose from 3 modes: snp,vtpm and snp-vtpm.Default mode is snp.",
|
Short: fmt.Sprintf("Validate and verify attestation information. You can define the confidential computing cloud provider (%s, %s, %s; %s is the default) and can choose from 3 modes: %s, %s and %s. Default mode is %s.", CCNone, CCAzure, CCGCP, CCNone, SNP, VTPM, SNPvTPM, SNP),
|
||||||
Example: `Based on mode:
|
Example: `Based on mode:
|
||||||
validate <attestationreportfilepath> --report_data <reportdata> --product <product data> //default
|
validate <attestationreportfilepath> --report_data <reportdata> --product <product data> --platform <cc platform> //default
|
||||||
validate --mode snp <attestationreportfilepath> --report_data <reportdata> --product <product data>
|
validate --mode snp <attestationreportfilepath> --report_data <reportdata> --product <product data>
|
||||||
validate --mode vtpm <attestationreportfilepath> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>
|
validate --mode vtpm <attestationreportfilepath> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>
|
||||||
validate --mode snp-vtpm <attestationreportfilepath> --report_data <reportdata> --product <product data> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>`,
|
validate --mode snp-vtpm <attestationreportfilepath> --report_data <reportdata> --product <product data> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>
|
||||||
|
validate --cloud none --mode snp <attestationreportfilepath> --report_data <reportdata> --product <product data>
|
||||||
|
validate --cloud azure --mode vtpm <attestationreportfilepath> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>
|
||||||
|
validate --cloud gcp --mode snp-vtpm <attestationreportfilepath> --report_data <reportdata> --product <product data> --nonce <noncevalue> --format <formatvalue> --output <outputvalue>`,
|
||||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mode, _ := cmd.Flags().GetString("mode")
|
mode, _ := cmd.Flags().GetString("mode")
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
@@ -359,38 +357,38 @@ func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
|||||||
|
|
||||||
// Validate flags based on the mode
|
// Validate flags based on the mode
|
||||||
switch mode {
|
switch mode {
|
||||||
case "snp":
|
case SNP:
|
||||||
if err := cmd.MarkFlagRequired("report_data"); err != nil {
|
if err := cmd.MarkFlagRequired("report_data"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'report_data' as required for SEV-SNP mode: %v", err)
|
return fmt.Errorf("failed to mark 'report_data' as required for SEV-%s mode: %v", SNP, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("product"); err != nil {
|
if err := cmd.MarkFlagRequired("product"); err != nil {
|
||||||
return fmt.Errorf("failed to mark flag as required: %v ❌ ", err)
|
return fmt.Errorf("failed to mark flag as required: %v ❌ ", err)
|
||||||
}
|
}
|
||||||
case "snp-vtpm":
|
case SNPvTPM:
|
||||||
if err := cmd.MarkFlagRequired("nonce"); err != nil {
|
if err := cmd.MarkFlagRequired("nonce"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'nonce' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'nonce' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("report_data"); err != nil {
|
if err := cmd.MarkFlagRequired("report_data"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'report_data' as required for SEV-SNP mode: %v", err)
|
return fmt.Errorf("failed to mark 'report_data' as required for SEV-%s mode: %v", SNP, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("product"); err != nil {
|
if err := cmd.MarkFlagRequired("product"); err != nil {
|
||||||
return fmt.Errorf("failed to mark flag as required: %v ❌ ", err)
|
return fmt.Errorf("failed to mark flag as required: %v ❌ ", err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("format"); err != nil {
|
if err := cmd.MarkFlagRequired("format"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'format' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'format' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("output"); err != nil {
|
if err := cmd.MarkFlagRequired("output"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'output' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'output' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
case "vtpm":
|
case VTPM:
|
||||||
if err := cmd.MarkFlagRequired("nonce"); err != nil {
|
if err := cmd.MarkFlagRequired("nonce"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'nonce' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'nonce' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("format"); err != nil {
|
if err := cmd.MarkFlagRequired("format"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'format' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'format' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
if err := cmd.MarkFlagRequired("output"); err != nil {
|
if err := cmd.MarkFlagRequired("output"); err != nil {
|
||||||
return fmt.Errorf("failed to mark 'output' as required for vTPM mode: %v", err)
|
return fmt.Errorf("failed to mark 'output' as required for %s mode: %v", VTPM, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown mode: %s", mode)
|
return fmt.Errorf("unknown mode: %s", mode)
|
||||||
@@ -399,13 +397,35 @@ func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
|||||||
},
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
mode, _ := cmd.Flags().GetString("mode")
|
mode, _ := cmd.Flags().GetString("mode")
|
||||||
|
cloud, _ := cmd.Flags().GetString("cloud")
|
||||||
|
|
||||||
|
output, err := createOutputFile()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create output file: %v ❌ ", err)
|
||||||
|
}
|
||||||
|
if closer, ok := output.(*os.File); ok {
|
||||||
|
defer closer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider attestation.Provider
|
||||||
|
switch cloud {
|
||||||
|
case CCNone:
|
||||||
|
provider = vtpm.New(nil, false, 0, output)
|
||||||
|
case CCAzure:
|
||||||
|
provider = azure.New(output)
|
||||||
|
case CCGCP:
|
||||||
|
provider = vtpm.New(nil, false, 0, output)
|
||||||
|
default:
|
||||||
|
provider = vtpm.New(nil, false, 0, output)
|
||||||
|
}
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case "snp":
|
case SNP:
|
||||||
return sevsnpverify(cmd, args)
|
return sevsnpverify(cmd, provider, args)
|
||||||
case "snp-vtpm":
|
case SNPvTPM:
|
||||||
return vtpmSevSnpverify(args)
|
return vtpmSevSnpverify(args, provider)
|
||||||
case "vtpm":
|
case VTPM:
|
||||||
return vtpmverify(args)
|
return vtpmverify(args, provider)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown mode: %s", mode)
|
return fmt.Errorf("unknown mode: %s", mode)
|
||||||
}
|
}
|
||||||
@@ -413,11 +433,18 @@ func (cli *CLI) NewValidateAttestationValidationCmd() *cobra.Command {
|
|||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
SilenceErrors: true,
|
SilenceErrors: true,
|
||||||
}
|
}
|
||||||
|
cmd.Flags().StringVar(
|
||||||
|
&cloud,
|
||||||
|
"cloud",
|
||||||
|
"none", // default CC provider
|
||||||
|
"The confidential computing cloud provider. Example: azure",
|
||||||
|
)
|
||||||
|
|
||||||
cmd.Flags().StringVar(
|
cmd.Flags().StringVar(
|
||||||
&mode,
|
&mode,
|
||||||
"mode",
|
"mode",
|
||||||
"snp", // default mode
|
"snp", // default mode
|
||||||
"The attestation validation mode. Example: sevsnp",
|
"The attestation validation mode. Example: snp",
|
||||||
)
|
)
|
||||||
|
|
||||||
// VTPM FLAGS
|
// VTPM FLAGS
|
||||||
@@ -659,7 +686,7 @@ func (cli *CLI) NewMeasureCmd(igvmBinaryPath string) *cobra.Command {
|
|||||||
return igvmmeasureCmd
|
return igvmmeasureCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func sevsnpverify(cmd *cobra.Command, args []string) error {
|
func sevsnpverify(cmd *cobra.Command, provider attestation.Provider, args []string) error {
|
||||||
cmd.Println("Checking attestation")
|
cmd.Println("Checking attestation")
|
||||||
|
|
||||||
attestationFile = string(args[0])
|
attestationFile = string(args[0])
|
||||||
@@ -669,20 +696,18 @@ func sevsnpverify(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
// This format is the attestation report in AMD's specified ABI format, immediately
|
// This format is the attestation report in AMD's specified ABI format, immediately
|
||||||
// followed by the certificate table bytes.
|
// followed by the certificate table bytes.
|
||||||
if len(attestation) < abi.ReportSize {
|
if len(attestationRaw) < abi.ReportSize {
|
||||||
return fmt.Errorf("attestation too small: got 0x%x bytes, need at least 0x%x bytes", len(attestation), abi.ReportSize)
|
return fmt.Errorf("attestation too small: got 0x%x bytes, need at least 0x%x bytes", len(attestationRaw), abi.ReportSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := parseAttestationConfig(); err != nil {
|
if err := parseAttestationConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
attestationPB, err := abi.ReportCertsToProto(attestation)
|
// Used for verification of SNP attestation report
|
||||||
if err != nil {
|
attestation.AttestationPolicy.Config = &cfg
|
||||||
return fmt.Errorf("failed to convert attestation bytes to struct %v ❌ ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quoteprovider.VerifyAndValidate(attestationPB, &cfg); err != nil {
|
if err := provider.VerifTeeAttestation(attestationRaw, cfg.Policy.ReportData); err != nil {
|
||||||
return fmt.Errorf("attestation validation and verification failed with error: %v ❌ ", err)
|
return fmt.Errorf("attestation validation and verification failed with error: %v ❌ ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,85 +737,40 @@ func parseAttestationConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtpmSevSnpverify(args []string) error {
|
func vtpmSevSnpverify(args []string, provider attestation.Provider) error {
|
||||||
attestation, err := returnvTPMAttestation(args)
|
attest, err := returnvTPMAttestation(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var teeAttestation *sevsnp.Attestation
|
|
||||||
switch attestation.GetTeeAttestation().(type) {
|
|
||||||
case *tpmAttest.Attestation_SevSnpAttestation:
|
|
||||||
teeAttestation = attestation.GetSevSnpAttestation()
|
|
||||||
default:
|
|
||||||
teeAttestation = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if teeAttestation == nil {
|
|
||||||
return fmt.Errorf("tee attestation not fetched")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := parseAttestationConfig(); err != nil {
|
if err := parseAttestationConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := quoteprovider.VerifyAndValidate(teeAttestation, &cfg); err != nil {
|
// Used for verification of SNP attestation report
|
||||||
return fmt.Errorf("attestation validation and verification failed with error: %v ❌ ", err)
|
attestation.AttestationPolicy.Config = &cfg
|
||||||
}
|
|
||||||
|
|
||||||
if err := verifyvTPM(attestation); err != nil {
|
if err := provider.VerifyAttestation(attest, cfg.Policy.ReportData, nonce); err != nil {
|
||||||
return err
|
return fmt.Errorf("attestation validation and verification failed with error: %v ❌ ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func vtpmverify(args []string) error {
|
func vtpmverify(args []string, provider attestation.Provider) error {
|
||||||
attestation, err := returnvTPMAttestation(args)
|
attestation, err := returnvTPMAttestation(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := verifyvTPM(attestation); err != nil {
|
if err := provider.VerifVTpmAttestation(attestation, nonce); err != nil {
|
||||||
return err
|
return fmt.Errorf("attestation validation and verification failed with error: %v ❌ ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyvTPM(attestation *tpmAttest.Attestation) error {
|
func returnvTPMAttestation(args []string) ([]byte, error) {
|
||||||
pub, err := tpm2.DecodePublic(attestation.GetAkPub())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cryptoPub, err := pub.Key()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ms, err := server.VerifyAttestation(attestation, server.VerifyOpts{Nonce: nonce, TrustedAKs: []crypto.PublicKey{cryptoPub}, TEEOpts: nil})
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out, err := marshalOptions.Marshal(ms)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
output, err := createOutputFile()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if closer, ok := output.(*os.File); ok {
|
|
||||||
defer closer.Close()
|
|
||||||
}
|
|
||||||
if _, err := output.Write(out); err != nil {
|
|
||||||
return fmt.Errorf("failed to write verified attestation report: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func returnvTPMAttestation(args []string) (*tpmAttest.Attestation, error) {
|
|
||||||
tpmAttestationFile = string(args[0])
|
tpmAttestationFile = string(args[0])
|
||||||
input, err := openInputFile()
|
input, err := openInputFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -806,8 +786,9 @@ func returnvTPMAttestation(args []string) (*tpmAttest.Attestation, error) {
|
|||||||
attestation := &tpmAttest.Attestation{}
|
attestation := &tpmAttest.Attestation{}
|
||||||
|
|
||||||
if format == FormatBinaryPB {
|
if format == FormatBinaryPB {
|
||||||
err = proto.Unmarshal(attestationBytes, attestation)
|
return attestationBytes, nil
|
||||||
} else if format == FormatTextProto {
|
} else if format == FormatTextProto {
|
||||||
|
unmarshalOptions := prototext.UnmarshalOptions{}
|
||||||
err = unmarshalOptions.Unmarshal(attestationBytes, attestation)
|
err = unmarshalOptions.Unmarshal(attestationBytes, attestation)
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("format should be either binarypb or textproto")
|
return nil, fmt.Errorf("format should be either binarypb or textproto")
|
||||||
@@ -816,7 +797,12 @@ func returnvTPMAttestation(args []string) (*tpmAttest.Attestation, error) {
|
|||||||
return nil, fmt.Errorf("fail to unmarshal attestation report: %v", err)
|
return nil, fmt.Errorf("fail to unmarshal attestation report: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return attestation, nil
|
attestationBytes, err = proto.Marshal(attestation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("fail to marshal vTPM attestation report: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return attestationBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func openInputFile() (io.Reader, error) {
|
func openInputFile() (io.Reader, error) {
|
||||||
@@ -926,9 +912,9 @@ func parseAttestationFile() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
attestation = file
|
attestationRaw = file
|
||||||
if isFileJSON(attestationFile) {
|
if isFileJSON(attestationFile) {
|
||||||
attestation, err = attesationFromJSON(attestation)
|
attestationRaw, err = attesationFromJSON(attestationRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+59
-10
@@ -16,7 +16,8 @@ import (
|
|||||||
"github.com/google/go-tpm-tools/proto/attest"
|
"github.com/google/go-tpm-tools/proto/attest"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation/azure"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/gcp"
|
"github.com/ultravioletrs/cocos/pkg/attestation/gcp"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
@@ -37,13 +38,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errDecode = errors.New("base64 string could not be decoded")
|
errDecode = errors.New("base64 string could not be decoded")
|
||||||
errDataLength = errors.New("data does not have an adequate length")
|
errDataLength = errors.New("data does not have an adequate length")
|
||||||
errReadingAttestationPolicyFile = errors.New("error while reading the attestation policy file")
|
errReadingAttestationPolicyFile = errors.New("error while reading the attestation policy file")
|
||||||
errUnmarshalJSON = errors.New("failed to unmarshal json")
|
errUnmarshalJSON = errors.New("failed to unmarshal json")
|
||||||
errMarshalJSON = errors.New("failed to marshal json")
|
errMarshalJSON = errors.New("failed to marshal json")
|
||||||
errWriteFile = errors.New("failed to write to file")
|
errWriteFile = errors.New("failed to write to file")
|
||||||
errAttestationPolicyField = errors.New("the specified field type does not exist in the attestation policy")
|
errAttestationPolicyField = errors.New("the specified field type does not exist in the attestation policy")
|
||||||
|
policy uint64 = 196639
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cli *CLI) NewAttestationPolicyCmd() *cobra.Command {
|
func (cli *CLI) NewAttestationPolicyCmd() *cobra.Command {
|
||||||
@@ -226,6 +228,53 @@ func (cli *CLI) NewDownloadGCPOvmfFile() *cobra.Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cli *CLI) NewAzureAttestationPolicy() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "azure",
|
||||||
|
Short: "Get attestation policy for Azure CVM",
|
||||||
|
Example: `azure <azure_maa_token_file> <token_nonce> <product_name>`,
|
||||||
|
Args: cobra.ExactArgs(3),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
token, err := os.ReadFile(args[0])
|
||||||
|
if err != nil {
|
||||||
|
printError(cmd, "Error reading attestation report file: %v ❌ ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce := []byte(args[1])
|
||||||
|
product := args[2]
|
||||||
|
|
||||||
|
config, err := azure.GenerateAttestationPolicy(string(token), product, policy, nonce)
|
||||||
|
if err != nil {
|
||||||
|
printError(cmd, "Error generating attestation policy: %v ❌ ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attestationPolicyJson, err := json.MarshalIndent(&config, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
printError(cmd, "Error marshaling attestation policy: %v ❌ ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile("attestation_policy.json", attestationPolicyJson, filePermission); err != nil {
|
||||||
|
printError(cmd, "Error writing attestation policy file: %v ❌ ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Println("Attestation policy file generated successfully ✅")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().Uint64Var(
|
||||||
|
&policy,
|
||||||
|
"policy",
|
||||||
|
policy,
|
||||||
|
"Policy of the guest CVM",
|
||||||
|
)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
func changeAttestationConfiguration(fileName, base64Data string, expectedLength int, field fieldType) error {
|
func changeAttestationConfiguration(fileName, base64Data string, expectedLength int, field fieldType) error {
|
||||||
data, err := base64.StdEncoding.DecodeString(base64Data)
|
data, err := base64.StdEncoding.DecodeString(base64Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -236,14 +285,14 @@ func changeAttestationConfiguration(fileName, base64Data string, expectedLength
|
|||||||
return errDataLength
|
return errDataLength
|
||||||
}
|
}
|
||||||
|
|
||||||
ac := config.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &config.PcrConfig{}}
|
ac := attestation.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
|
|
||||||
f, err := os.ReadFile(fileName)
|
f, err := os.ReadFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(errReadingAttestationPolicyFile, err)
|
return errors.Wrap(errReadingAttestationPolicyFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = config.ReadAttestationPolicyFromByte(f, &ac); err != nil {
|
if err = attestation.ReadAttestationPolicyFromByte(f, &ac); err != nil {
|
||||||
return errors.Wrap(errUnmarshalJSON, err)
|
return errors.Wrap(errUnmarshalJSON, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChangeAttestationConfiguration(t *testing.T) {
|
func TestChangeAttestationConfiguration(t *testing.T) {
|
||||||
@@ -19,7 +19,7 @@ func TestChangeAttestationConfiguration(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.Remove(tmpfile.Name())
|
defer os.Remove(tmpfile.Name())
|
||||||
|
|
||||||
initialConfig := config.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &config.PcrConfig{}}
|
initialConfig := attestation.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
|
|
||||||
initialJSON, err := json.Marshal(initialConfig)
|
initialJSON, err := json.Marshal(initialConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -87,8 +87,8 @@ func TestChangeAttestationConfiguration(t *testing.T) {
|
|||||||
content, err := os.ReadFile(tmpfile.Name())
|
content, err := os.ReadFile(tmpfile.Name())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ap := config.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &config.PcrConfig{}}
|
ap := attestation.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
err = config.ReadAttestationPolicyFromByte(content, &ap)
|
err = attestation.ReadAttestationPolicyFromByte(content, &ap)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
decodedData, _ := base64.StdEncoding.DecodeString(tt.base64Data)
|
decodedData, _ := base64.StdEncoding.DecodeString(tt.base64Data)
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ func TestNewValidateAttestationValidationCmdDefaults(t *testing.T) {
|
|||||||
cmd := cli.NewValidateAttestationValidationCmd()
|
cmd := cli.NewValidateAttestationValidationCmd()
|
||||||
|
|
||||||
assert.Equal(t, "validate", cmd.Use)
|
assert.Equal(t, "validate", cmd.Use)
|
||||||
assert.Equal(t, "Validate and verify attestation information. You can choose from 3 modes: snp,vtpm and snp-vtpm.Default mode is snp.", cmd.Short)
|
expectedMessage := fmt.Sprintf("Validate and verify attestation information. You can define the confidential computing cloud provider (%s, %s, %s; %s is the default) and can choose from 3 modes: %s, %s and %s. Default mode is %s.", CCNone, CCAzure, CCGCP, CCNone, SNP, VTPM, SNPvTPM, SNP)
|
||||||
|
assert.Equal(t, expectedMessage, cmd.Short)
|
||||||
|
|
||||||
assert.Equal(t, fmt.Sprint(defaultMinimumTcb), cmd.Flag("minimum_tcb").Value.String())
|
assert.Equal(t, fmt.Sprint(defaultMinimumTcb), cmd.Flag("minimum_tcb").Value.String())
|
||||||
assert.Equal(t, fmt.Sprint(defaultMinimumLaunchTcb), cmd.Flag("minimum_lauch_tcb").Value.String())
|
assert.Equal(t, fmt.Sprint(defaultMinimumLaunchTcb), cmd.Flag("minimum_lauch_tcb").Value.String())
|
||||||
@@ -394,7 +395,7 @@ func TestParseFiles(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = parseTrustedKeys()
|
err = parseTrustedKeys()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []byte("test attestation"), attestation)
|
assert.Equal(t, []byte("test attestation"), attestationRaw)
|
||||||
assert.Len(t, cfg.Policy.TrustedAuthorKeys, 1)
|
assert.Len(t, cfg.Policy.TrustedAuthorKeys, 1)
|
||||||
assert.Len(t, cfg.Policy.TrustedIdKeys, 1)
|
assert.Len(t, cfg.Policy.TrustedIdKeys, 1)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
"github.com/google/go-sev-guest/verify/trust"
|
"github.com/google/go-sev-guest/verify/trust"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -27,8 +27,8 @@ func (cli *CLI) NewCABundleCmd(fileSavePath string) *cobra.Command {
|
|||||||
Example: "ca-bundle <path_to_platform_info_json>",
|
Example: "ca-bundle <path_to_platform_info_json>",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
attestationConfiguration := config.Config{Config: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &config.PcrConfig{}}
|
attestationConfiguration := attestation.Config{Config: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
err := config.ReadAttestationPolicy(args[0], &attestationConfiguration)
|
err := attestation.ReadAttestationPolicy(args[0], &attestationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printError(cmd, "Error while reading manifest: %v ❌ ", err)
|
printError(cmd, "Error while reading manifest: %v ❌ ", err)
|
||||||
return
|
return
|
||||||
|
|||||||
+31
-38
@@ -8,7 +8,6 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
@@ -20,8 +19,7 @@ import (
|
|||||||
mglog "github.com/absmach/magistrala/logger"
|
mglog "github.com/absmach/magistrala/logger"
|
||||||
"github.com/absmach/magistrala/pkg/prometheus"
|
"github.com/absmach/magistrala/pkg/prometheus"
|
||||||
"github.com/caarlos0/env/v11"
|
"github.com/caarlos0/env/v11"
|
||||||
"github.com/google/go-sev-guest/client"
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
"github.com/ultravioletrs/cocos/agent/api"
|
"github.com/ultravioletrs/cocos/agent/api"
|
||||||
"github.com/ultravioletrs/cocos/agent/cvms"
|
"github.com/ultravioletrs/cocos/agent/cvms"
|
||||||
@@ -29,9 +27,8 @@ import (
|
|||||||
"github.com/ultravioletrs/cocos/agent/cvms/server"
|
"github.com/ultravioletrs/cocos/agent/cvms/server"
|
||||||
"github.com/ultravioletrs/cocos/agent/events"
|
"github.com/ultravioletrs/cocos/agent/events"
|
||||||
agentlogger "github.com/ultravioletrs/cocos/internal/logger"
|
agentlogger "github.com/ultravioletrs/cocos/internal/logger"
|
||||||
attestationconfig "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/azure"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider/mocks"
|
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||||
cvmsgrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc/cvm"
|
cvmsgrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc/cvm"
|
||||||
@@ -52,6 +49,10 @@ type config struct {
|
|||||||
AgentGrpcHost string `env:"AGENT_GRPC_HOST" envDefault:"0.0.0.0"`
|
AgentGrpcHost string `env:"AGENT_GRPC_HOST" envDefault:"0.0.0.0"`
|
||||||
CAUrl string `env:"AGENT_CVM_CA_URL" envDefault:""`
|
CAUrl string `env:"AGENT_CVM_CA_URL" envDefault:""`
|
||||||
CVMId string `env:"AGENT_CVM_ID" envDefault:""`
|
CVMId string `env:"AGENT_CVM_ID" envDefault:""`
|
||||||
|
AgentMaaURL string `env:"AGENT_MAA_URL" envDefault:"https://sharedeus2.eus2.attest.azure.net"`
|
||||||
|
AgentOSBuild string `env:"AGENT_OS_BUILD" envDefault:"UVC"`
|
||||||
|
AgentOSDistro string `env:"AGENT_OS_DISTRO" envDefault:"UVC"`
|
||||||
|
AgentOSType string `env:"AGENT_OS_TYPE" envDefault:"UVC"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -85,22 +86,19 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var qp client.LeveledQuoteProvider
|
var provider attestation.Provider
|
||||||
vtpmAttest := vtpm.Attest
|
ccPlatform := attestation.CCPlatform()
|
||||||
|
|
||||||
if !sevGuesDeviceExists() {
|
switch ccPlatform {
|
||||||
logger.Info("SEV-SNP device not found")
|
case attestation.SNP:
|
||||||
qpMock := new(mocks.LeveledQuoteProvider)
|
provider = vtpm.New(nil, false, uint(cfg.Vmpl), nil)
|
||||||
qpMock.On("GetRawQuoteAtLevel", mock.Anything, mock.Anything).Return([]uint8{}, errors.New("SEV-SNP device not found"))
|
case attestation.SNPvTPM:
|
||||||
qp = qpMock
|
provider = vtpm.New(nil, true, uint(cfg.Vmpl), nil)
|
||||||
vtpmAttest = vtpm.EmptyAttest
|
case attestation.Azure:
|
||||||
} else {
|
provider = azure.New(nil)
|
||||||
qp, err = quoteprovider.GetLeveledQuoteProvider()
|
case attestation.NoCC:
|
||||||
if err != nil {
|
logger.Info("TEE device not found")
|
||||||
logger.Error(fmt.Sprintf("failed to create quote provider %s", err.Error()))
|
provider = &attestation.EmptyProvider{}
|
||||||
exitCode = 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cvmGrpcConfig := pkggrpc.CVMClientConfig{}
|
cvmGrpcConfig := pkggrpc.CVMClientConfig{}
|
||||||
@@ -146,7 +144,11 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
svc := newService(ctx, logger, eventSvc, qp, cfg.Vmpl, vtpmAttest)
|
azure.MaaURL = cfg.AgentMaaURL
|
||||||
|
maa.OSBuild = cfg.AgentOSBuild
|
||||||
|
maa.OSDistro = cfg.AgentOSDistro
|
||||||
|
maa.OSType = cfg.AgentOSType
|
||||||
|
svc := newService(ctx, logger, eventSvc, provider, cfg.Vmpl)
|
||||||
|
|
||||||
if err := os.MkdirAll(storageDir, 0o755); err != nil {
|
if err := os.MkdirAll(storageDir, 0o755); err != nil {
|
||||||
logger.Error(fmt.Sprintf("failed to create storage directory: %s", err))
|
logger.Error(fmt.Sprintf("failed to create storage directory: %s", err))
|
||||||
@@ -154,7 +156,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mc, err := cvmsapi.NewClient(pc, svc, eventsLogsQueue, logger, server.NewServer(logger, svc, cfg.AgentGrpcHost, qp, cfg.CAUrl, cfg.CVMId), storageDir, reconnectFn, cvmGRPCClient)
|
mc, err := cvmsapi.NewClient(pc, svc, eventsLogsQueue, logger, server.NewServer(logger, svc, cfg.AgentGrpcHost, cfg.CAUrl, cfg.CVMId), storageDir, reconnectFn, cvmGRPCClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err.Error())
|
logger.Error(err.Error())
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
@@ -180,7 +182,7 @@ func main() {
|
|||||||
return mc.Process(ctx, cancel)
|
return mc.Process(ctx, cancel)
|
||||||
})
|
})
|
||||||
|
|
||||||
attestation, certSerialNumber, err := attestationFromCert(ctx, cvmGrpcConfig.ClientCert, svc)
|
attest, certSerialNumber, err := attestationFromCert(ctx, cvmGrpcConfig.ClientCert, svc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(fmt.Sprintf("failed to get attestation: %s", err))
|
logger.Error(fmt.Sprintf("failed to get attestation: %s", err))
|
||||||
exitCode = 1
|
exitCode = 1
|
||||||
@@ -190,7 +192,7 @@ func main() {
|
|||||||
eventsLogsQueue <- &cvms.ClientStreamMessage{
|
eventsLogsQueue <- &cvms.ClientStreamMessage{
|
||||||
Message: &cvms.ClientStreamMessage_VTPMattestationReport{
|
Message: &cvms.ClientStreamMessage_VTPMattestationReport{
|
||||||
VTPMattestationReport: &cvms.AttestationResponse{
|
VTPMattestationReport: &cvms.AttestationResponse{
|
||||||
File: attestation,
|
File: attest,
|
||||||
CertSerialNumber: certSerialNumber,
|
CertSerialNumber: certSerialNumber,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -201,8 +203,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, qp client.LeveledQuoteProvider, vmpl int, vtpmAttest vtpm.VtpmAttest) agent.Service {
|
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, provider attestation.Provider, vmpl int) agent.Service {
|
||||||
svc := agent.New(ctx, logger, eventSvc, qp, vmpl, vtpmAttest)
|
svc := agent.New(ctx, logger, eventSvc, provider, vmpl)
|
||||||
|
|
||||||
svc = api.LoggingMiddleware(svc, logger)
|
svc = api.LoggingMiddleware(svc, logger)
|
||||||
counter, latency := prometheus.MakeMetrics(svcName, "api")
|
counter, latency := prometheus.MakeMetrics(svcName, "api")
|
||||||
@@ -211,15 +213,6 @@ func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Servic
|
|||||||
return svc
|
return svc
|
||||||
}
|
}
|
||||||
|
|
||||||
func sevGuesDeviceExists() bool {
|
|
||||||
d, err := client.OpenDevice()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
d.Close()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func attestationFromCert(ctx context.Context, certFilePath string, svc agent.Service) ([]byte, string, error) {
|
func attestationFromCert(ctx context.Context, certFilePath string, svc agent.Service) ([]byte, string, error) {
|
||||||
if certFilePath == "" {
|
if certFilePath == "" {
|
||||||
return nil, "", nil
|
return nil, "", nil
|
||||||
@@ -238,10 +231,10 @@ func attestationFromCert(ctx context.Context, certFilePath string, svc agent.Ser
|
|||||||
|
|
||||||
nonceSNP := sha512.Sum512(certFile)
|
nonceSNP := sha512.Sum512(certFile)
|
||||||
nonceVTPM := sha256.Sum256(certFile)
|
nonceVTPM := sha256.Sum256(certFile)
|
||||||
attestation, err := svc.Attestation(ctx, nonceSNP, nonceVTPM, attestationconfig.SNPvTPM)
|
attest, err := svc.Attestation(ctx, nonceSNP, nonceVTPM, attestation.SNPvTPM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return attestation, certx509.SerialNumber.String(), nil
|
return attest, certx509.SerialNumber.String(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ func main() {
|
|||||||
attestationPolicyCmd.AddCommand(cliSVC.NewAddHostDataCmd())
|
attestationPolicyCmd.AddCommand(cliSVC.NewAddHostDataCmd())
|
||||||
attestationPolicyCmd.AddCommand(cliSVC.NewGCPAttestationPolicy())
|
attestationPolicyCmd.AddCommand(cliSVC.NewGCPAttestationPolicy())
|
||||||
attestationPolicyCmd.AddCommand(cliSVC.NewDownloadGCPOvmfFile())
|
attestationPolicyCmd.AddCommand(cliSVC.NewDownloadGCPOvmfFile())
|
||||||
|
attestationPolicyCmd.AddCommand(cliSVC.NewAzureAttestationPolicy())
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
logErrorCmd(*rootCmd, err)
|
logErrorCmd(*rootCmd, err)
|
||||||
|
|||||||
+1
-1
@@ -112,7 +112,7 @@ func main() {
|
|||||||
manager.RegisterManagerServiceServer(srv, managergrpc.NewServer(svc))
|
manager.RegisterManagerServiceServer(srv, managergrpc.NewServer(svc))
|
||||||
}
|
}
|
||||||
|
|
||||||
gs := grpcserver.New(ctx, cancel, svcName, managerGRPCConfig, registerManagerServiceServer, logger, nil, nil, "", "")
|
gs := grpcserver.New(ctx, cancel, svcName, managerGRPCConfig, registerManagerServiceServer, logger, nil, "", "")
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
return gs.Start()
|
return gs.Start()
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/storage v1.51.0
|
cloud.google.com/go/storage v1.51.0
|
||||||
github.com/golang/protobuf v1.5.4
|
github.com/edgelesssys/go-azguestattestation v0.0.0-20250408071817-8c4457b235ff
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||||
github.com/google/gce-tcb-verifier v0.3.1
|
github.com/google/gce-tcb-verifier v0.3.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,10 +53,10 @@ require (
|
|||||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||||
github.com/gofrs/uuid/v5 v5.3.0 // indirect
|
github.com/gofrs/uuid/v5 v5.3.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/google/certificate-transparency-go v1.1.8 // indirect
|
||||||
github.com/google/certificate-transparency-go v1.1.2 // indirect
|
|
||||||
github.com/google/go-attestation v0.5.1 // indirect
|
github.com/google/go-attestation v0.5.1 // indirect
|
||||||
github.com/google/go-eventlog v0.0.2-0.20241003021507-01bb555f7cba // indirect
|
github.com/google/go-eventlog v0.0.2-0.20241003021507-01bb555f7cba // indirect
|
||||||
github.com/google/go-tspi v0.3.0 // indirect
|
github.com/google/go-tspi v0.3.0 // indirect
|
||||||
@@ -95,11 +96,12 @@ require (
|
|||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/docker v28.0.4+incompatible
|
github.com/docker/docker v28.0.1+incompatible
|
||||||
github.com/go-kit/log v0.2.1 // indirect
|
github.com/go-kit/log v0.2.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/google/go-configfs-tsm v0.3.3-0.20240919001351-b4b5b84fdcbc // indirect
|
github.com/google/go-configfs-tsm v0.3.3-0.20240919001351-b4b5b84fdcbc // indirect
|
||||||
github.com/google/go-tpm v0.9.3
|
github.com/google/go-tpm v0.9.3
|
||||||
github.com/google/go-tpm-tools v0.4.4
|
github.com/google/go-tpm-tools v0.4.4
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import (
|
|||||||
certscli "github.com/absmach/certs/cli"
|
certscli "github.com/absmach/certs/cli"
|
||||||
"github.com/absmach/certs/errors"
|
"github.com/absmach/certs/errors"
|
||||||
certssdk "github.com/absmach/certs/sdk"
|
certssdk "github.com/absmach/certs/sdk"
|
||||||
"github.com/google/go-sev-guest/client"
|
|
||||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||||
"github.com/ultravioletrs/cocos/agent/auth"
|
"github.com/ultravioletrs/cocos/agent/auth"
|
||||||
"github.com/ultravioletrs/cocos/internal/server"
|
"github.com/ultravioletrs/cocos/internal/server"
|
||||||
@@ -61,7 +60,6 @@ type Server struct {
|
|||||||
server.BaseServer
|
server.BaseServer
|
||||||
server *grpc.Server
|
server *grpc.Server
|
||||||
registerService serviceRegister
|
registerService serviceRegister
|
||||||
quoteProvider client.LeveledQuoteProvider
|
|
||||||
authSvc auth.Authenticator
|
authSvc auth.Authenticator
|
||||||
health *health.Server
|
health *health.Server
|
||||||
caUrl string
|
caUrl string
|
||||||
@@ -76,7 +74,7 @@ type serviceRegister func(srv *grpc.Server)
|
|||||||
|
|
||||||
var _ server.Server = (*Server)(nil)
|
var _ server.Server = (*Server)(nil)
|
||||||
|
|
||||||
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.ServerConfiguration, registerService serviceRegister, logger *slog.Logger, qp client.LeveledQuoteProvider, authSvc auth.Authenticator, caUrl string, cvmId string) server.Server {
|
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.ServerConfiguration, registerService serviceRegister, logger *slog.Logger, authSvc auth.Authenticator, caUrl string, cvmId string) server.Server {
|
||||||
base := config.GetBaseConfig()
|
base := config.GetBaseConfig()
|
||||||
listenFullAddress := fmt.Sprintf("%s:%s", base.Host, base.Port)
|
listenFullAddress := fmt.Sprintf("%s:%s", base.Host, base.Port)
|
||||||
return &Server{
|
return &Server{
|
||||||
@@ -89,7 +87,6 @@ func New(ctx context.Context, cancel context.CancelFunc, name string, config ser
|
|||||||
Logger: logger,
|
Logger: logger,
|
||||||
},
|
},
|
||||||
registerService: registerService,
|
registerService: registerService,
|
||||||
quoteProvider: qp,
|
|
||||||
authSvc: authSvc,
|
authSvc: authSvc,
|
||||||
caUrl: caUrl,
|
caUrl: caUrl,
|
||||||
cvmId: cvmId,
|
cvmId: cvmId,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
authmocks "github.com/ultravioletrs/cocos/agent/auth/mocks"
|
authmocks "github.com/ultravioletrs/cocos/agent/auth/mocks"
|
||||||
"github.com/ultravioletrs/cocos/internal/server"
|
"github.com/ultravioletrs/cocos/internal/server"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider/mocks"
|
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/test/bufconn"
|
"google.golang.org/grpc/test/bufconn"
|
||||||
@@ -70,10 +69,9 @@ func TestNew(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
logger := slog.Default()
|
logger := slog.Default()
|
||||||
qp := new(mocks.LeveledQuoteProvider)
|
|
||||||
authSvc := new(authmocks.Authenticator)
|
authSvc := new(authmocks.Authenticator)
|
||||||
|
|
||||||
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, qp, authSvc, "", "")
|
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, authSvc, "", "")
|
||||||
|
|
||||||
assert.NotNil(t, srv)
|
assert.NotNil(t, srv)
|
||||||
assert.IsType(t, &Server{}, srv)
|
assert.IsType(t, &Server{}, srv)
|
||||||
@@ -120,10 +118,9 @@ func TestServerStartWithTLSFile(t *testing.T) {
|
|||||||
|
|
||||||
logBuffer := &ThreadSafeBuffer{}
|
logBuffer := &ThreadSafeBuffer{}
|
||||||
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||||
qp := new(mocks.LeveledQuoteProvider)
|
|
||||||
authSvc := new(authmocks.Authenticator)
|
authSvc := new(authmocks.Authenticator)
|
||||||
|
|
||||||
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, qp, authSvc, "", "")
|
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, authSvc, "", "")
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@@ -167,10 +164,9 @@ func TestServerStartWithmTLSFile(t *testing.T) {
|
|||||||
|
|
||||||
logBuffer := &ThreadSafeBuffer{}
|
logBuffer := &ThreadSafeBuffer{}
|
||||||
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||||
qp := new(mocks.LeveledQuoteProvider)
|
|
||||||
authSvc := new(authmocks.Authenticator)
|
authSvc := new(authmocks.Authenticator)
|
||||||
|
|
||||||
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, qp, authSvc, "", "")
|
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, authSvc, "", "")
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@@ -207,10 +203,9 @@ func TestServerStop(t *testing.T) {
|
|||||||
}
|
}
|
||||||
buf := &ThreadSafeBuffer{}
|
buf := &ThreadSafeBuffer{}
|
||||||
logger := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
logger := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||||
qp := new(mocks.LeveledQuoteProvider)
|
|
||||||
authSvc := new(authmocks.Authenticator)
|
authSvc := new(authmocks.Authenticator)
|
||||||
|
|
||||||
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, qp, authSvc, "", "")
|
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, authSvc, "", "")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err := srv.Start()
|
err := srv.Start()
|
||||||
@@ -399,10 +394,9 @@ func TestServerInitializationAndStartup(t *testing.T) {
|
|||||||
|
|
||||||
logBuffer := &ThreadSafeBuffer{}
|
logBuffer := &ThreadSafeBuffer{}
|
||||||
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||||
qp := new(mocks.LeveledQuoteProvider)
|
|
||||||
authSvc := new(authmocks.Authenticator)
|
authSvc := new(authmocks.Authenticator)
|
||||||
|
|
||||||
srv := New(ctx, cancel, "TestServer", tc.config, func(srv *grpc.Server) {}, logger, qp, authSvc, "", "")
|
srv := New(ctx, cancel, "TestServer", tc.config, func(srv *grpc.Server) {}, logger, authSvc, "", "")
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
"github.com/ultravioletrs/cocos/manager/qemu"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/cmdconfig"
|
"github.com/ultravioletrs/cocos/pkg/attestation/cmdconfig"
|
||||||
"github.com/virtee/sev-snp-measure-go/cpuid"
|
"github.com/virtee/sev-snp-measure-go/cpuid"
|
||||||
"github.com/virtee/sev-snp-measure-go/guest"
|
"github.com/virtee/sev-snp-measure-go/guest"
|
||||||
@@ -63,9 +63,9 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
attestationPolicy := config.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &config.PcrConfig{}}
|
attestationPolicy := attestation.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
|
|
||||||
if err = config.ReadAttestationPolicyFromByte(stdOutByte, &attestationPolicy); err != nil {
|
if err = attestation.ReadAttestationPolicyFromByte(stdOutByte, &attestationPolicy); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -22,7 +22,7 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
"github.com/ultravioletrs/cocos/manager/qemu"
|
||||||
"github.com/ultravioletrs/cocos/manager/vm"
|
"github.com/ultravioletrs/cocos/manager/vm"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/cmdconfig"
|
"github.com/ultravioletrs/cocos/pkg/attestation/cmdconfig"
|
||||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
@@ -181,9 +181,9 @@ func (ms *managerService) CreateVM(ctx context.Context, req *CreateReq) (string,
|
|||||||
return "", id, errors.Wrap(ErrFailedToCreateAttestationPolicy, err)
|
return "", id, errors.Wrap(ErrFailedToCreateAttestationPolicy, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
attestationPolicy := config.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &config.PcrConfig{}}
|
attestationPolicy := attestation.Config{Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
|
|
||||||
if err = config.ReadAttestationPolicyFromByte(stdOutByte, &attestationPolicy); err != nil {
|
if err = attestation.ReadAttestationPolicyFromByte(stdOutByte, &attestationPolicy); err != nil {
|
||||||
return "", id, errors.Wrap(ErrUnmarshalFailed, err)
|
return "", id, errors.Wrap(ErrUnmarshalFailed, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-14
@@ -41,13 +41,6 @@ packages:
|
|||||||
dir: "{{.InterfaceDir}}/mocks"
|
dir: "{{.InterfaceDir}}/mocks"
|
||||||
filename: "state.go"
|
filename: "state.go"
|
||||||
mockname: "{{.InterfaceName}}"
|
mockname: "{{.InterfaceName}}"
|
||||||
github.com/ultravioletrs/cocos/internal/logger:
|
|
||||||
interfaces:
|
|
||||||
io.Writer:
|
|
||||||
config:
|
|
||||||
dir: "{{.InterfaceDir}}/mocks"
|
|
||||||
filename: "io_writer.go"
|
|
||||||
mockname: "{{.InterfaceName}}"
|
|
||||||
github.com/ultravioletrs/cocos/internal/server:
|
github.com/ultravioletrs/cocos/internal/server:
|
||||||
interfaces:
|
interfaces:
|
||||||
Server:
|
Server:
|
||||||
@@ -105,13 +98,6 @@ packages:
|
|||||||
dir: "{{.InterfaceDir}}/mocks"
|
dir: "{{.InterfaceDir}}/mocks"
|
||||||
filename: "server.go"
|
filename: "server.go"
|
||||||
mockname: "{{.InterfaceName}}"
|
mockname: "{{.InterfaceName}}"
|
||||||
github.com/google/go-sev-guest/client:
|
|
||||||
interfaces:
|
|
||||||
LeveledQuoteProvider:
|
|
||||||
config:
|
|
||||||
dir: "./pkg/attestation/quoteprovider/mocks"
|
|
||||||
filename: "QuoteProvider.go"
|
|
||||||
mockname: "{{.InterfaceName}}"
|
|
||||||
github.com/ultravioletrs/cocos/agent/cvms/api/grpc/storage:
|
github.com/ultravioletrs/cocos/agent/cvms/api/grpc/storage:
|
||||||
interfaces:
|
interfaces:
|
||||||
Storage:
|
Storage:
|
||||||
@@ -126,3 +112,10 @@ packages:
|
|||||||
dir: "{{.InterfaceDir}}/mocks"
|
dir: "{{.InterfaceDir}}/mocks"
|
||||||
filename: "client.go"
|
filename: "client.go"
|
||||||
mockname: "{{.InterfaceName}}"
|
mockname: "{{.InterfaceName}}"
|
||||||
|
github.com/ultravioletrs/cocos/pkg/attestation:
|
||||||
|
interfaces:
|
||||||
|
Provider:
|
||||||
|
config:
|
||||||
|
dir: "{{.InterfaceDir}}/mocks"
|
||||||
|
filename: "attestation.go"
|
||||||
|
mockname: "{{.InterfaceName}}"
|
||||||
|
|||||||
+49
-55
@@ -5,14 +5,15 @@ package atls
|
|||||||
|
|
||||||
// #cgo LDFLAGS: -lssl -lcrypto
|
// #cgo LDFLAGS: -lssl -lcrypto
|
||||||
// #include "extensions.h"
|
// #include "extensions.h"
|
||||||
|
// #include <string.h>
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/sha3"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"runtime/cgo"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -20,15 +21,12 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation/azure"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
NoTee int = iota
|
|
||||||
AmdSevSnp
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
noError = 0
|
noError = 0
|
||||||
errorZeroReturn = 6
|
errorZeroReturn = 6
|
||||||
@@ -37,6 +35,7 @@ const (
|
|||||||
errorSyscall = 5
|
errorSyscall = 5
|
||||||
errorSsl = 1
|
errorSsl = 1
|
||||||
waitTime = 2
|
waitTime = 2
|
||||||
|
vmpl2 = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -51,57 +50,42 @@ var (
|
|||||||
errConnCreate = errors.New("could not create connection")
|
errConnCreate = errors.New("could not create connection")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ValidationVerification func(data1, data2, data3, data4 []byte) error
|
func formTeeData(pubKey []byte, teeNonce []byte) []byte {
|
||||||
type FetchAttestation func(data1, data2, data3 []byte) ([]byte, error)
|
combined := append(pubKey, teeNonce...)
|
||||||
|
sum := sha3.Sum512(combined)
|
||||||
func registerFetchAttestation(callback FetchAttestation) uintptr {
|
return sum[:]
|
||||||
handle := cgo.NewHandle(callback)
|
|
||||||
return uintptr(handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerValidationVerification(callback ValidationVerification) uintptr {
|
func getPlatformProvider(platformType attestation.PlatformType, pubKey []byte) (attestation.Provider, error) {
|
||||||
handle := cgo.NewHandle(callback)
|
switch platformType {
|
||||||
return uintptr(handle)
|
case attestation.SNPvTPM:
|
||||||
}
|
return vtpm.New(pubKey, true, vmpl2, nil), nil
|
||||||
|
case attestation.Azure:
|
||||||
//export validationVerificationCallback
|
return azure.New(nil), nil
|
||||||
func validationVerificationCallback(teeType C.int) uintptr {
|
|
||||||
switch int(teeType) {
|
|
||||||
case NoTee:
|
|
||||||
return uintptr(0)
|
|
||||||
case AmdSevSnp:
|
|
||||||
return registerValidationVerification(vtpm.VTPMVerify)
|
|
||||||
default:
|
default:
|
||||||
return uintptr(0)
|
return nil, fmt.Errorf("unsupported platform type: %d", platformType)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//export fetchAttestationCallback
|
|
||||||
func fetchAttestationCallback(teeType C.int) uintptr {
|
|
||||||
switch int(teeType) {
|
|
||||||
case NoTee:
|
|
||||||
return uintptr(0)
|
|
||||||
case AmdSevSnp:
|
|
||||||
return registerFetchAttestation(vtpm.FetchATLSQuote)
|
|
||||||
default:
|
|
||||||
return uintptr(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//export callVerificationValidationCallback
|
//export callVerificationValidationCallback
|
||||||
func callVerificationValidationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKeyLen C.int, quote *C.uchar, quoteSize C.int, teeNonce *C.uchar, nonce *C.uchar) C.int {
|
func callVerificationValidationCallback(platformType C.int, pubKey *C.uchar, pubKeyLen C.int, attestReport *C.uchar, attestReportSize C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar) C.int {
|
||||||
handle := cgo.Handle(callbackHandle)
|
|
||||||
defer handle.Delete()
|
|
||||||
|
|
||||||
callback := handle.Value().(ValidationVerification)
|
|
||||||
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
||||||
attestationReport := C.GoBytes(unsafe.Pointer(quote), quoteSize)
|
teeNonceData := C.GoBytes(unsafe.Pointer(teeNonceByte), quoteprovider.Nonce)
|
||||||
teeData := C.GoBytes(unsafe.Pointer(teeNonce), quoteprovider.Nonce)
|
vTPMNonce := C.GoBytes(unsafe.Pointer(vTPMNonceByte), vtpm.Nonce)
|
||||||
nonceData := C.GoBytes(unsafe.Pointer(nonce), vtpm.Nonce)
|
pType := attestation.PlatformType(int(platformType))
|
||||||
|
attestationReport := C.GoBytes(unsafe.Pointer(attestReport), attestReportSize)
|
||||||
|
|
||||||
|
teeData := formTeeData(pubKeyCert, teeNonceData)
|
||||||
|
|
||||||
err := callback(attestationReport, pubKeyCert, teeData, nonceData)
|
provider, err := getPlatformProvider(pType, pubKeyCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "callback failed %v", err)
|
fmt.Fprintf(os.Stderr, "no attestation provider found for platform type %s", err.Error())
|
||||||
|
return C.int(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = provider.VerifyAttestation(attestationReport, teeData, vTPMNonce)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "verification callback failed %s", err.Error())
|
||||||
return C.int(-1)
|
return C.int(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,18 +93,23 @@ func callVerificationValidationCallback(callbackHandle uintptr, pubKey *C.uchar,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export callFetchAttestationCallback
|
//export callFetchAttestationCallback
|
||||||
func callFetchAttestationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKeyLen C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar, outlen *C.ulong) *C.uchar {
|
func callFetchAttestationCallback(platformType C.int, pubKey *C.uchar, pubKeyLen C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar, outlen *C.ulong) *C.uchar {
|
||||||
handle := cgo.Handle(callbackHandle)
|
|
||||||
defer handle.Delete()
|
|
||||||
|
|
||||||
callback := handle.Value().(FetchAttestation)
|
|
||||||
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
||||||
teeNonceData := C.GoBytes(unsafe.Pointer(teeNonceByte), quoteprovider.Nonce)
|
teeNonceData := C.GoBytes(unsafe.Pointer(teeNonceByte), quoteprovider.Nonce)
|
||||||
vTPMNonce := C.GoBytes(unsafe.Pointer(vTPMNonceByte), vtpm.Nonce)
|
vTPMNonce := C.GoBytes(unsafe.Pointer(vTPMNonceByte), vtpm.Nonce)
|
||||||
|
pType := attestation.PlatformType(int(platformType))
|
||||||
|
|
||||||
quote, err := callback(pubKeyCert, teeNonceData, vTPMNonce)
|
teeData := formTeeData(pubKeyCert, teeNonceData)
|
||||||
|
|
||||||
|
provider, err := getPlatformProvider(pType, pubKeyCert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "attestation callback returned nil")
|
fmt.Fprintf(os.Stderr, "no attestation provider found for platform type %s", err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
quote, err := provider.Attestation(teeData, vTPMNonce)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "attestation callback returned nil: %s", err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +125,11 @@ func callFetchAttestationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKe
|
|||||||
return (*C.uchar)(resultC)
|
return (*C.uchar)(resultC)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export returnCCPlatformType
|
||||||
|
func returnCCPlatformType() int32 {
|
||||||
|
return int32(attestation.CCPlatform())
|
||||||
|
}
|
||||||
|
|
||||||
type ATLSServerListener struct {
|
type ATLSServerListener struct {
|
||||||
tlsListener *C.tls_server_connection
|
tlsListener *C.tls_server_connection
|
||||||
}
|
}
|
||||||
@@ -252,7 +246,7 @@ func (c *ATLSConn) Read(b []byte) (int, error) {
|
|||||||
return 0, syscall.ECONNRESET // return connection reset error.
|
return 0, syscall.ECONNRESET // return connection reset error.
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "SSL error occurred: %d\n", errCode)
|
fmt.Fprintf(os.Stderr, "SSL error occurred: %d\n", errCode)
|
||||||
return 0, fmt.Errorf("SSL error\n")
|
return 0, fmt.Errorf("SSL error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-53
@@ -7,41 +7,28 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
extern int callVerificationValidationCallback(uintptr_t callbackHandle, const u_char* pubKey, int pubKeyLen, const u_char* quote, int quoteSize, const u_char* teeNonce, const u_char* nonce);
|
extern int callVerificationValidationCallback(int platformType, const u_char* pubKey, int pubKeyLen, const u_char* quote, int quoteSize, const u_char* teeNonceByte, const u_char* vTPMNonceByte);
|
||||||
extern u_char* callFetchAttestationCallback(uintptr_t callbackHandle, const u_char* pubKey, int pubKeyLen, const u_char* teeNonceByte, const u_char* vTPMNonceByte, unsigned long* outlen);
|
extern u_char* callFetchAttestationCallback(int platformType, const u_char* pubKey, int pubKeyLen, const u_char* teeNonceByte, const u_char* vTPMNonceByte, unsigned long* outlen);
|
||||||
extern uintptr_t validationVerificationCallback(int teeType);
|
extern uintptr_t validationVerificationCallback(int teeType);
|
||||||
extern uintptr_t fetchAttestationCallback(int teeType);
|
extern uintptr_t getPlatformTypeHandle(int platformType, u_char *teeNonce, u_char *vtpmNonce);
|
||||||
|
extern int returnCCPlatformType();
|
||||||
|
|
||||||
int triggerVerificationValidationCallback(uintptr_t callbackHandle, u_char* pub_key, int pub_key_len, u_char *quote, int quote_size, u_char *tee_nonce, u_char *vtpm_nonce) {
|
int triggerVerificationValidationCallback(int platformType, u_char* pub_key, int pub_key_len, u_char *quote, int quote_size, u_char *tee_nonce, u_char *vtpm_nonce) {
|
||||||
if (quote == NULL || vtpm_nonce == NULL || tee_nonce == NULL || pub_key == NULL) {
|
if (quote == NULL || vtpm_nonce == NULL || tee_nonce == NULL || pub_key == NULL) {
|
||||||
fprintf(stderr, "attestation and noce and public key cannot be NULL\n");
|
fprintf(stderr, "attestation and noce and public key cannot be NULL\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return callVerificationValidationCallback(callbackHandle, pub_key, pub_key_len, quote, quote_size, tee_nonce, vtpm_nonce);
|
return callVerificationValidationCallback(platformType, pub_key, pub_key_len, quote, quote_size, tee_nonce, vtpm_nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
u_char* triggerFetchAttestationCallback(uintptr_t callback_handle, u_char* pub_key, int pub_key_len, char *tee_nonce, char *vtpm_nonce, unsigned long *outlen) {
|
u_char* triggerFetchAttestationCallback(int platformType, u_char* pub_key, int pub_key_len, char *tee_nonce, char *vtpm_nonce, unsigned long *outlen) {
|
||||||
if(tee_nonce == NULL || vtpm_nonce == NULL) {
|
if(tee_nonce == NULL || vtpm_nonce == NULL) {
|
||||||
fprintf(stderr, "Report data cannot be NULL");
|
fprintf(stderr, "Report data cannot be NULL");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return callFetchAttestationCallback(callback_handle, pub_key, pub_key_len, tee_nonce, vtpm_nonce, outlen);
|
return callFetchAttestationCallback(platformType, pub_key, pub_key_len, tee_nonce, vtpm_nonce, outlen);
|
||||||
}
|
|
||||||
|
|
||||||
int check_sev_snp() {
|
|
||||||
int fd = open(SEV_GUEST_DRIVER_PATH, O_RDONLY);
|
|
||||||
|
|
||||||
if (fd == -1) {
|
|
||||||
perror("Error opening /dev/sev-guest");
|
|
||||||
fprintf(stderr, "SEV guest driver is not available.\n");
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -78,9 +65,9 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ext_data != NULL) {
|
if (ext_data != NULL) {
|
||||||
if (RAND_bytes(ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE) != 1) {
|
if (RAND_bytes(ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE) != 1) {
|
||||||
perror("could not generate random bytes for vtpm nonce, will use SSL client random");
|
perror("could not generate random bytes for vtpm nonce, will use SSL client random");
|
||||||
SSL_get_client_random(s, ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE);
|
SSL_get_client_random(s, ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RAND_bytes(ext_data->er.tee_nonce, REPORT_DATA_SIZE) != 1) {
|
if (RAND_bytes(ext_data->er.tee_nonce, REPORT_DATA_SIZE) != 1) {
|
||||||
@@ -94,10 +81,8 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(er->vtpm_nonce, ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE);
|
memcpy(er->vtpm_nonce, ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||||
memcpy(er->tee_nonce, ext_data->er.tee_nonce, REPORT_DATA_SIZE);
|
memcpy(er->tee_nonce, ext_data->er.tee_nonce, REPORT_DATA_SIZE);
|
||||||
er->tee_type = AMD_TEE;
|
|
||||||
ext_data->er.tee_type = AMD_TEE;
|
|
||||||
|
|
||||||
*out = (const u_char *)er;
|
*out = (const u_char *)er;
|
||||||
*outlen = sizeof(evidence_request);
|
*outlen = sizeof(evidence_request);
|
||||||
@@ -116,19 +101,8 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_sev_snp() > 0) {
|
*platform_type = returnCCPlatformType();
|
||||||
*platform_type = AMD_TEE;
|
ext_data->platform_type = *platform_type;
|
||||||
} else {
|
|
||||||
*platform_type = NO_TEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*platform_type != ext_data->er.tee_type) || (*platform_type == NO_TEE)) {
|
|
||||||
*platform_type = NO_TEE;
|
|
||||||
ext_data->er.tee_type = NO_TEE;
|
|
||||||
} else {
|
|
||||||
ext_data->er.tee_type = AMD_TEE;
|
|
||||||
ext_data->fetch_attestation_handler = fetchAttestationCallback(ext_data->er.tee_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = (u_char*)platform_type;
|
*out = (u_char*)platform_type;
|
||||||
*outlen = sizeof(int32_t);
|
*outlen = sizeof(int32_t);
|
||||||
@@ -164,9 +138,8 @@ int evidence_request_ext_parse_cb(SSL *s, unsigned int ext_type,
|
|||||||
evidence_request *er = (evidence_request*)in;
|
evidence_request *er = (evidence_request*)in;
|
||||||
|
|
||||||
if (ext_data != NULL) {
|
if (ext_data != NULL) {
|
||||||
memcpy(ext_data->er.vtpm_nonce, er->vtpm_nonce, CLIENT_RANDOM_SIZE);
|
memcpy(ext_data->er.vtpm_nonce, er->vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||||
memcpy(ext_data->er.tee_nonce, er->tee_nonce, REPORT_DATA_SIZE);
|
memcpy(ext_data->er.tee_nonce, er->tee_nonce, REPORT_DATA_SIZE);
|
||||||
ext_data->er.tee_type = er->tee_type;
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "parse_arg is NULL\n");
|
fprintf(stderr, "parse_arg is NULL\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -175,18 +148,11 @@ int evidence_request_ext_parse_cb(SSL *s, unsigned int ext_type,
|
|||||||
}
|
}
|
||||||
case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS:
|
case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS:
|
||||||
{
|
{
|
||||||
int *tee_type = (int*)in;
|
int *platform_type = (int*)in;
|
||||||
tls_extension_data *ext_data = (tls_extension_data*)parse_arg;
|
tls_extension_data *ext_data = (tls_extension_data*)parse_arg;
|
||||||
|
|
||||||
if (ext_data != NULL) {
|
if (ext_data != NULL) {
|
||||||
ext_data->er.tee_type = *tee_type;
|
ext_data->platform_type = *platform_type;
|
||||||
|
|
||||||
if (ext_data->er.tee_type != NO_TEE) {
|
|
||||||
ext_data->verification_validation_handler = validationVerificationCallback(ext_data->er.tee_type);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "must use a TEE for aTLS\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "parse_arg is NULL\n");
|
fprintf(stderr, "parse_arg is NULL\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -253,7 +219,7 @@ int attestation_certificate_ext_add_cb(SSL *s, unsigned int ext_type,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
quote = triggerFetchAttestationCallback(ext_data->fetch_attestation_handler, pubkey_buf, pubkey_len, ext_data->er.tee_nonce, ext_data->er.vtpm_nonce, &len);
|
quote = triggerFetchAttestationCallback(ext_data->platform_type, pubkey_buf, pubkey_len, ext_data->er.tee_nonce, ext_data->er.vtpm_nonce, &len);
|
||||||
if (quote == NULL) {
|
if (quote == NULL) {
|
||||||
fprintf(stderr, "attestation report is NULL\n");
|
fprintf(stderr, "attestation report is NULL\n");
|
||||||
*al = SSL_AD_INTERNAL_ERROR;
|
*al = SSL_AD_INTERNAL_ERROR;
|
||||||
@@ -291,7 +257,6 @@ int attestation_certificate_ext_parse_cb(SSL *s, unsigned int ext_type,
|
|||||||
switch (context)
|
switch (context)
|
||||||
{
|
{
|
||||||
case SSL_EXT_CLIENT_HELLO:
|
case SSL_EXT_CLIENT_HELLO:
|
||||||
// Return 1 so the server can return the custom certificate extension.
|
|
||||||
return 1;
|
return 1;
|
||||||
case SSL_EXT_TLS1_3_CERTIFICATE:
|
case SSL_EXT_TLS1_3_CERTIFICATE:
|
||||||
{
|
{
|
||||||
@@ -324,7 +289,7 @@ int attestation_certificate_ext_parse_cb(SSL *s, unsigned int ext_type,
|
|||||||
}
|
}
|
||||||
memcpy(quote, in, inlen);
|
memcpy(quote, in, inlen);
|
||||||
|
|
||||||
res = triggerVerificationValidationCallback(ext_data->verification_validation_handler,
|
res = triggerVerificationValidationCallback(ext_data->platform_type,
|
||||||
pubkey_buf,
|
pubkey_buf,
|
||||||
pubkey_len,
|
pubkey_len,
|
||||||
quote,
|
quote,
|
||||||
|
|||||||
+3
-11
@@ -7,25 +7,19 @@
|
|||||||
#define EVIDENCE_REQUEST_HELLO_EXTENSION_TYPE 65
|
#define EVIDENCE_REQUEST_HELLO_EXTENSION_TYPE 65
|
||||||
#define ATTESTATION_CERTIFICATE_EXTENSION_TYPE 66
|
#define ATTESTATION_CERTIFICATE_EXTENSION_TYPE 66
|
||||||
#define REPORT_DATA_SIZE 64
|
#define REPORT_DATA_SIZE 64
|
||||||
#define CLIENT_RANDOM_SIZE 32
|
#define NONCE_RANDOM_SIZE 32
|
||||||
#define TLS_CLIENT_CTX 0
|
#define TLS_CLIENT_CTX 0
|
||||||
#define TLS_SERVER_CTX 1
|
#define TLS_SERVER_CTX 1
|
||||||
|
|
||||||
#define SEV_GUEST_DRIVER_PATH "/dev/sev-guest"
|
|
||||||
#define NO_TEE 0
|
|
||||||
#define AMD_TEE 1
|
|
||||||
|
|
||||||
typedef struct evidence_request
|
typedef struct evidence_request
|
||||||
{
|
{
|
||||||
int tee_type;
|
char vtpm_nonce[NONCE_RANDOM_SIZE];
|
||||||
char vtpm_nonce[CLIENT_RANDOM_SIZE];
|
|
||||||
char tee_nonce[REPORT_DATA_SIZE];
|
char tee_nonce[REPORT_DATA_SIZE];
|
||||||
} evidence_request;
|
} evidence_request;
|
||||||
|
|
||||||
typedef struct tls_extension_data
|
typedef struct tls_extension_data
|
||||||
{
|
{
|
||||||
uintptr_t fetch_attestation_handler;
|
int platform_type;
|
||||||
uintptr_t verification_validation_handler;
|
|
||||||
evidence_request er;
|
evidence_request er;
|
||||||
} tls_extension_data;
|
} tls_extension_data;
|
||||||
|
|
||||||
@@ -37,7 +31,6 @@ typedef struct tls_server_connection
|
|||||||
char* key;
|
char* key;
|
||||||
int key_len;
|
int key_len;
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
uintptr_t fetch_attestation_handler;
|
|
||||||
} tls_server_connection;
|
} tls_server_connection;
|
||||||
|
|
||||||
typedef struct tls_connection
|
typedef struct tls_connection
|
||||||
@@ -61,7 +54,6 @@ int set_socket_read_timeout(tls_connection* conn, int timeout_sec, int timeout_u
|
|||||||
int set_socket_write_timeout(tls_connection* conn, int timeout_sec, int timeout_usec);
|
int set_socket_write_timeout(tls_connection* conn, int timeout_sec, int timeout_usec);
|
||||||
char* tls_return_addr(struct sockaddr_storage *addr);
|
char* tls_return_addr(struct sockaddr_storage *addr);
|
||||||
int tls_return_port(struct sockaddr_storage *addr);
|
int tls_return_port(struct sockaddr_storage *addr);
|
||||||
int compute_sha256_of_public_key(X509 *cert, unsigned char *hash);
|
|
||||||
|
|
||||||
// Extensions
|
// Extensions
|
||||||
void evidence_request_ext_free_cb(SSL *s, unsigned int ext_type,
|
void evidence_request_ext_free_cb(SSL *s, unsigned int ext_type,
|
||||||
|
|||||||
+1
-2
@@ -289,9 +289,8 @@ tls_connection* tls_server_accept(tls_server_connection *tls_server) {
|
|||||||
goto cleanup_fd;
|
goto cleanup_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set file descriptor and assign handlers
|
// Set file descriptor
|
||||||
conn->socket_fd = client_fd;
|
conn->socket_fd = client_fd;
|
||||||
conn->tls_ext_data.fetch_attestation_handler = tls_server->fetch_attestation_handler;
|
|
||||||
SSL_set_fd(conn->ssl, client_fd);
|
SSL_set_fd(conn->ssl, client_fd);
|
||||||
|
|
||||||
// Get local address
|
// Get local address
|
||||||
|
|||||||
@@ -1,23 +1,35 @@
|
|||||||
// Copyright (c) Ultraviolet
|
// Copyright (c) Ultraviolet
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package config
|
package attestation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
|
"github.com/google/go-sev-guest/client"
|
||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
|
"github.com/google/go-tpm/legacy/tpm2"
|
||||||
"google.golang.org/protobuf/encoding/protojson"
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AttestationType int32
|
type PlatformType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SNP AttestationType = iota
|
SNP PlatformType = iota
|
||||||
VTPM
|
VTPM
|
||||||
SNPvTPM
|
SNPvTPM
|
||||||
|
Azure
|
||||||
|
NoCC
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
azureMetadataUrl = "http://169.254.169.254/metadata/instance"
|
||||||
|
azureApiVersion = "2021-02-01"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -43,6 +55,20 @@ type Config struct {
|
|||||||
*PcrConfig
|
*PcrConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ccCheck struct {
|
||||||
|
checkFunc func() bool
|
||||||
|
platform PlatformType
|
||||||
|
}
|
||||||
|
|
||||||
|
type Provider interface {
|
||||||
|
Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error)
|
||||||
|
TeeAttestation(teeNonce []byte) ([]byte, error)
|
||||||
|
VTpmAttestation(vTpmNonce []byte) ([]byte, error)
|
||||||
|
VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error
|
||||||
|
VerifTeeAttestation(report []byte, teeNonce []byte) error
|
||||||
|
VerifVTpmAttestation(report []byte, vTpmNonce []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config) error {
|
func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config) error {
|
||||||
if policyPath != "" {
|
if policyPath != "" {
|
||||||
policyData, err := os.ReadFile(policyPath)
|
policyData, err := os.ReadFile(policyPath)
|
||||||
@@ -69,3 +95,64 @@ func ReadAttestationPolicyFromByte(policyData []byte, attestationConfiguration *
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CCPlatform returns the type of the confidential computing platform.
|
||||||
|
func CCPlatform() PlatformType {
|
||||||
|
checks := []ccCheck{
|
||||||
|
{SevGuestvTPMExists, SNPvTPM},
|
||||||
|
{SevGuesDeviceExists, SNP},
|
||||||
|
{isAzureVM, Azure},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range checks {
|
||||||
|
if c.checkFunc() {
|
||||||
|
return c.platform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NoCC
|
||||||
|
}
|
||||||
|
|
||||||
|
func SevGuesDeviceExists() bool {
|
||||||
|
d, err := client.OpenDevice()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
d.Close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func SevGuestvTPMExists() bool {
|
||||||
|
d, err := tpm2.OpenTPM()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
d.Close()
|
||||||
|
|
||||||
|
return SevGuesDeviceExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAzureVM() bool {
|
||||||
|
client := &http.Client{}
|
||||||
|
url := fmt.Sprintf("%s?api-version=%s", azureMetadataUrl, azureApiVersion)
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", url, nil)
|
||||||
|
req.Header.Add("Metadata", "true")
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusOK {
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(body) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
// Copyright (c) Ultraviolet
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package azure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
|
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/google/go-sev-guest/abi"
|
||||||
|
"github.com/google/go-sev-guest/kds"
|
||||||
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
|
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||||
|
"github.com/google/go-sev-guest/tools/lib/report"
|
||||||
|
"github.com/google/go-tpm-tools/proto/attest"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
|
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var MaaURL = "https://sharedeus2.eus2.attest.azure.net"
|
||||||
|
|
||||||
|
var _ attestation.Provider = (*provider)(nil)
|
||||||
|
|
||||||
|
type provider struct {
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(writer io.Writer) attestation.Provider {
|
||||||
|
return provider{writer: writer}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||||
|
var tokenNonce [vtpm.Nonce]byte
|
||||||
|
copy(tokenNonce[:], teeNonce)
|
||||||
|
|
||||||
|
params, err := maa.NewParameters(context.Background(), tokenNonce[:], http.DefaultClient, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get report: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
snpReport, err := report.ParseAttestation(params.SNPReport, "bin")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse SNP report: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
quote, err := vtpm.FetchQuote(vTpmNonce)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch quote: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
quote.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
||||||
|
SevSnpAttestation: snpReport,
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto.Marshal(quote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||||
|
var tokenNonce [vtpm.Nonce]byte
|
||||||
|
copy(tokenNonce[:], teeNonce)
|
||||||
|
|
||||||
|
params, err := maa.NewParameters(context.Background(), tokenNonce[:], http.DefaultClient, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get report: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return params.SNPReport, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||||
|
quote, err := vtpm.FetchQuote(vTpmNonce)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, errors.Wrap(vtpm.ErrFetchQuote, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto.Marshal(quote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||||
|
attestationReport, err := abi.ReportCertsToProto(report)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return quoteprovider.VerifyAttestationReportTLS(attestationReport, teeNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||||
|
return vtpm.VerifyQuote(report, nil, vTpmNonce, a.writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||||
|
var tokenNonce [vtpm.Nonce]byte
|
||||||
|
copy(tokenNonce[:], teeNonce)
|
||||||
|
|
||||||
|
quote := &attest.Attestation{}
|
||||||
|
err := proto.Unmarshal(report, quote)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal vTPM quote: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
snpReport := quote.GetSevSnpAttestation()
|
||||||
|
if err = quoteprovider.VerifyAttestationReportTLS(snpReport, nil); err != nil {
|
||||||
|
return fmt.Errorf("failed to verify vTPM attestation report: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateAttestationPolicy(token string, product string, policy uint64, nonce []byte) (*attestation.Config, error) {
|
||||||
|
claims, err := validateToken(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to validate token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateClaims(claims, nonce); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to validate claims: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tee, ok := claims["x-ms-isolation-tee"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get tee from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
familyIdString, ok := tee["x-ms-sevsnpvm-familyId"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get familyId from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
familyId, err := hex.DecodeString(familyIdString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode familyId: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageIdString, ok := tee["x-ms-sevsnpvm-imageId"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get imageId from claims")
|
||||||
|
}
|
||||||
|
imageId, err := hex.DecodeString(imageIdString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode imageId: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
measurementString, ok := tee["x-ms-sevsnpvm-launchmeasurement"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get measurement from claims")
|
||||||
|
}
|
||||||
|
measurement, err := hex.DecodeString(measurementString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode measurement: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bootloaderVersion, ok := tee["x-ms-sevsnpvm-bootloader-svn"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get bootloader version from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
teeVersion, ok := tee["x-ms-sevsnpvm-tee-svn"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get tee version from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
snpVersion, ok := tee["x-ms-sevsnpvm-snpfw-svn"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get snp version from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
microcodeVersion, ok := tee["x-ms-sevsnpvm-microcode-svn"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get microcode version from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
minimalTCBParts := kds.TCBParts{
|
||||||
|
BlSpl: uint8(bootloaderVersion),
|
||||||
|
TeeSpl: uint8(teeVersion),
|
||||||
|
SnpSpl: uint8(snpVersion),
|
||||||
|
UcodeSpl: uint8(microcodeVersion),
|
||||||
|
}
|
||||||
|
|
||||||
|
minimalTCB, err := kds.ComposeTCBParts(minimalTCBParts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to compose TCB parts: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
guestSVN, ok := tee["x-ms-sevsnpvm-guestsvn"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get guest SVN from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
idKeyDigestString, ok := tee["x-ms-sevsnpvm-idkeydigest"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get idKeyDigest from claims")
|
||||||
|
}
|
||||||
|
idKeyDigest, err := hex.DecodeString(idKeyDigestString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode idKeyDigest: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reportIDString, ok := tee["x-ms-sevsnpvm-reportid"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("failed to get reportID from claims")
|
||||||
|
}
|
||||||
|
reportID, err := hex.DecodeString(reportIDString)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode reportID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sevProduct := quoteprovider.GetProductName(product)
|
||||||
|
|
||||||
|
return &attestation.Config{
|
||||||
|
Config: &check.Config{
|
||||||
|
RootOfTrust: &check.RootOfTrust{
|
||||||
|
CheckCrl: true,
|
||||||
|
},
|
||||||
|
Policy: &check.Policy{
|
||||||
|
ImageId: imageId,
|
||||||
|
FamilyId: familyId,
|
||||||
|
Measurement: measurement,
|
||||||
|
MinimumGuestSvn: uint32(guestSVN),
|
||||||
|
MinimumTcb: uint64(minimalTCB),
|
||||||
|
TrustedIdKeyHashes: [][]byte{idKeyDigest},
|
||||||
|
ReportId: reportID,
|
||||||
|
Product: &sevsnp.SevProduct{Name: sevProduct},
|
||||||
|
Policy: policy,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateToken(token string) (map[string]interface{}, error) {
|
||||||
|
unverifiedToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
jku, jkuOk := unverifiedToken.Header["jku"].(string)
|
||||||
|
if !jkuOk {
|
||||||
|
return nil, fmt.Errorf("token is missing jku or kid in header")
|
||||||
|
}
|
||||||
|
|
||||||
|
MaaUrlCerts := MaaURL
|
||||||
|
if MaaURL == "" {
|
||||||
|
MaaUrlCerts = jku
|
||||||
|
}
|
||||||
|
|
||||||
|
keySet, err := maa.GetKeySet(context.Background(), MaaUrlCerts, http.DefaultClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get key set: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := maa.ValidateToken(token, keySet)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to validate token: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateClaims(claims map[string]interface{}, nonce []byte) error {
|
||||||
|
runtime, ok := claims["x-ms-runtime"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("failed to get runtime from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, ok := runtime["client-payload"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("failed to get client payload from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenNonce, ok := payload["nonce"].(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("failed to get nonce from claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokenNonce != base64.StdEncoding.EncodeToString(nonce) {
|
||||||
|
return fmt.Errorf("nonce mismatch: expected %s, got %s", base64.StdEncoding.EncodeToString(nonce), tokenNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) Ultraviolet
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package attestation
|
||||||
|
|
||||||
|
import cocosai "github.com/ultravioletrs/cocos"
|
||||||
|
|
||||||
|
var _ Provider = (*EmptyProvider)(nil)
|
||||||
|
|
||||||
|
type EmptyProvider struct{}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||||
|
return cocosai.EmbeddedAttestation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||||
|
return cocosai.EmbeddedAttestation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||||
|
return cocosai.EmbeddedAttestation, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmptyProvider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -9,12 +9,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"github.com/google/gce-tcb-verifier/proto/endorsement"
|
"github.com/google/gce-tcb-verifier/proto/endorsement"
|
||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||||
"github.com/google/go-sev-guest/tools/lib/report"
|
"github.com/google/go-sev-guest/tools/lib/report"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -77,8 +77,8 @@ func GetLaunchEndorsement(ctx context.Context, measurement384 string) (*endorsem
|
|||||||
return &goldenUEFI, nil
|
return &goldenUEFI, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateAttestationPolicy(endorsement *endorsement.VMGoldenMeasurement, vcpuNum uint32) (*config.Config, error) {
|
func GenerateAttestationPolicy(endorsement *endorsement.VMGoldenMeasurement, vcpuNum uint32) (*attestation.Config, error) {
|
||||||
attestationPolicy := config.Config{PcrConfig: &config.PcrConfig{}, Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}}
|
attestationPolicy := attestation.Config{PcrConfig: &attestation.PcrConfig{}, Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}}
|
||||||
attestationPolicy.Config.Policy.Policy = endorsement.SevSnp.Policy
|
attestationPolicy.Config.Policy.Policy = endorsement.SevSnp.Policy
|
||||||
attestationPolicy.Config.Policy.Measurement = endorsement.SevSnp.Measurements[vcpuNum]
|
attestationPolicy.Config.Policy.Measurement = endorsement.SevSnp.Measurements[vcpuNum]
|
||||||
attestationPolicy.Config.RootOfTrust.DisallowNetwork = false
|
attestationPolicy.Config.RootOfTrust.DisallowNetwork = false
|
||||||
|
|||||||
@@ -0,0 +1,352 @@
|
|||||||
|
// Copyright (c) Ultraviolet
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Code generated by mockery v2.53.3. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
// Provider is an autogenerated mock type for the Provider type
|
||||||
|
type Provider struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
type Provider_Expecter struct {
|
||||||
|
mock *mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_m *Provider) EXPECT() *Provider_Expecter {
|
||||||
|
return &Provider_Expecter{mock: &_m.Mock}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attestation provides a mock function with given fields: teeNonce, vTpmNonce
|
||||||
|
func (_m *Provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||||
|
ret := _m.Called(teeNonce, vTpmNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Attestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []byte
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte, []byte) ([]byte, error)); ok {
|
||||||
|
return rf(teeNonce, vTpmNonce)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte, []byte) []byte); ok {
|
||||||
|
r0 = rf(teeNonce, vTpmNonce)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func([]byte, []byte) error); ok {
|
||||||
|
r1 = rf(teeNonce, vTpmNonce)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_Attestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Attestation'
|
||||||
|
type Provider_Attestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attestation is a helper method to define mock.On call
|
||||||
|
// - teeNonce []byte
|
||||||
|
// - vTpmNonce []byte
|
||||||
|
func (_e *Provider_Expecter) Attestation(teeNonce interface{}, vTpmNonce interface{}) *Provider_Attestation_Call {
|
||||||
|
return &Provider_Attestation_Call{Call: _e.mock.On("Attestation", teeNonce, vTpmNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_Attestation_Call) Run(run func(teeNonce []byte, vTpmNonce []byte)) *Provider_Attestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte), args[1].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_Attestation_Call) Return(_a0 []byte, _a1 error) *Provider_Attestation_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_Attestation_Call) RunAndReturn(run func([]byte, []byte) ([]byte, error)) *Provider_Attestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// TeeAttestation provides a mock function with given fields: teeNonce
|
||||||
|
func (_m *Provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||||
|
ret := _m.Called(teeNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for TeeAttestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []byte
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
|
||||||
|
return rf(teeNonce)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
|
||||||
|
r0 = rf(teeNonce)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func([]byte) error); ok {
|
||||||
|
r1 = rf(teeNonce)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_TeeAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TeeAttestation'
|
||||||
|
type Provider_TeeAttestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// TeeAttestation is a helper method to define mock.On call
|
||||||
|
// - teeNonce []byte
|
||||||
|
func (_e *Provider_Expecter) TeeAttestation(teeNonce interface{}) *Provider_TeeAttestation_Call {
|
||||||
|
return &Provider_TeeAttestation_Call{Call: _e.mock.On("TeeAttestation", teeNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_TeeAttestation_Call) Run(run func(teeNonce []byte)) *Provider_TeeAttestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_TeeAttestation_Call) Return(_a0 []byte, _a1 error) *Provider_TeeAttestation_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_TeeAttestation_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Provider_TeeAttestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// VTpmAttestation provides a mock function with given fields: vTpmNonce
|
||||||
|
func (_m *Provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||||
|
ret := _m.Called(vTpmNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for VTpmAttestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []byte
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
|
||||||
|
return rf(vTpmNonce)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
|
||||||
|
r0 = rf(vTpmNonce)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func([]byte) error); ok {
|
||||||
|
r1 = rf(vTpmNonce)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_VTpmAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VTpmAttestation'
|
||||||
|
type Provider_VTpmAttestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// VTpmAttestation is a helper method to define mock.On call
|
||||||
|
// - vTpmNonce []byte
|
||||||
|
func (_e *Provider_Expecter) VTpmAttestation(vTpmNonce interface{}) *Provider_VTpmAttestation_Call {
|
||||||
|
return &Provider_VTpmAttestation_Call{Call: _e.mock.On("VTpmAttestation", vTpmNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VTpmAttestation_Call) Run(run func(vTpmNonce []byte)) *Provider_VTpmAttestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VTpmAttestation_Call) Return(_a0 []byte, _a1 error) *Provider_VTpmAttestation_Call {
|
||||||
|
_c.Call.Return(_a0, _a1)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VTpmAttestation_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Provider_VTpmAttestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifTeeAttestation provides a mock function with given fields: report, teeNonce
|
||||||
|
func (_m *Provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||||
|
ret := _m.Called(report, teeNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for VerifTeeAttestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
|
||||||
|
r0 = rf(report, teeNonce)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_VerifTeeAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifTeeAttestation'
|
||||||
|
type Provider_VerifTeeAttestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifTeeAttestation is a helper method to define mock.On call
|
||||||
|
// - report []byte
|
||||||
|
// - teeNonce []byte
|
||||||
|
func (_e *Provider_Expecter) VerifTeeAttestation(report interface{}, teeNonce interface{}) *Provider_VerifTeeAttestation_Call {
|
||||||
|
return &Provider_VerifTeeAttestation_Call{Call: _e.mock.On("VerifTeeAttestation", report, teeNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifTeeAttestation_Call) Run(run func(report []byte, teeNonce []byte)) *Provider_VerifTeeAttestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte), args[1].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifTeeAttestation_Call) Return(_a0 error) *Provider_VerifTeeAttestation_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifTeeAttestation_Call) RunAndReturn(run func([]byte, []byte) error) *Provider_VerifTeeAttestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifVTpmAttestation provides a mock function with given fields: report, vTpmNonce
|
||||||
|
func (_m *Provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||||
|
ret := _m.Called(report, vTpmNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for VerifVTpmAttestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
|
||||||
|
r0 = rf(report, vTpmNonce)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_VerifVTpmAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifVTpmAttestation'
|
||||||
|
type Provider_VerifVTpmAttestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifVTpmAttestation is a helper method to define mock.On call
|
||||||
|
// - report []byte
|
||||||
|
// - vTpmNonce []byte
|
||||||
|
func (_e *Provider_Expecter) VerifVTpmAttestation(report interface{}, vTpmNonce interface{}) *Provider_VerifVTpmAttestation_Call {
|
||||||
|
return &Provider_VerifVTpmAttestation_Call{Call: _e.mock.On("VerifVTpmAttestation", report, vTpmNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifVTpmAttestation_Call) Run(run func(report []byte, vTpmNonce []byte)) *Provider_VerifVTpmAttestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte), args[1].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifVTpmAttestation_Call) Return(_a0 error) *Provider_VerifVTpmAttestation_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifVTpmAttestation_Call) RunAndReturn(run func([]byte, []byte) error) *Provider_VerifVTpmAttestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAttestation provides a mock function with given fields: report, teeNonce, vTpmNonce
|
||||||
|
func (_m *Provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||||
|
ret := _m.Called(report, teeNonce, vTpmNonce)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for VerifyAttestation")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func([]byte, []byte, []byte) error); ok {
|
||||||
|
r0 = rf(report, teeNonce, vTpmNonce)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider_VerifyAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyAttestation'
|
||||||
|
type Provider_VerifyAttestation_Call struct {
|
||||||
|
*mock.Call
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAttestation is a helper method to define mock.On call
|
||||||
|
// - report []byte
|
||||||
|
// - teeNonce []byte
|
||||||
|
// - vTpmNonce []byte
|
||||||
|
func (_e *Provider_Expecter) VerifyAttestation(report interface{}, teeNonce interface{}, vTpmNonce interface{}) *Provider_VerifyAttestation_Call {
|
||||||
|
return &Provider_VerifyAttestation_Call{Call: _e.mock.On("VerifyAttestation", report, teeNonce, vTpmNonce)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifyAttestation_Call) Run(run func(report []byte, teeNonce []byte, vTpmNonce []byte)) *Provider_VerifyAttestation_Call {
|
||||||
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
|
run(args[0].([]byte), args[1].([]byte), args[2].([]byte))
|
||||||
|
})
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifyAttestation_Call) Return(_a0 error) *Provider_VerifyAttestation_Call {
|
||||||
|
_c.Call.Return(_a0)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *Provider_VerifyAttestation_Call) RunAndReturn(run func([]byte, []byte, []byte) error) *Provider_VerifyAttestation_Call {
|
||||||
|
_c.Call.Return(run)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
|
// The first argument is typically a *testing.T value.
|
||||||
|
func NewProvider(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *Provider {
|
||||||
|
mock := &Provider{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright (c) Ultraviolet
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
//go:build embed
|
|
||||||
// +build embed
|
|
||||||
|
|
||||||
package quoteprovider
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/google/go-sev-guest/client"
|
|
||||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
|
||||||
pb "github.com/google/go-sev-guest/proto/sevsnp"
|
|
||||||
cocosai "github.com/ultravioletrs/cocos"
|
|
||||||
)
|
|
||||||
|
|
||||||
const Nonce = 64
|
|
||||||
|
|
||||||
var _ client.LeveledQuoteProvider = (*embeddedQuoteProvider)(nil)
|
|
||||||
|
|
||||||
type embeddedQuoteProvider struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLeveledQuoteProvider() (client.LeveledQuoteProvider, error) {
|
|
||||||
return &embeddedQuoteProvider{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRawQuoteAtLevel returns the SEV quote for the given report data and VMPL.
|
|
||||||
func (e *embeddedQuoteProvider) GetRawQuoteAtLevel(reportData [64]byte, vmpl uint) ([]byte, error) {
|
|
||||||
return cocosai.EmbeddedAttestation, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSupported returns true if the SEV platform is supported.
|
|
||||||
func (e *embeddedQuoteProvider) IsSupported() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Product returns the SEV product information.
|
|
||||||
// unimplemented since it is deprecated and not used.
|
|
||||||
func (e *embeddedQuoteProvider) Product() *pb.SevProduct {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
|
||||||
return cocosai.EmbeddedAttestation, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyAttestationReportTLS(attestation *sevsnp.Attestation, reportData []byte) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
// Copyright (c) Ultraviolet
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Code generated by mockery v2.53.3. DO NOT EDIT.
|
|
||||||
|
|
||||||
package mocks
|
|
||||||
|
|
||||||
import (
|
|
||||||
sevsnp "github.com/google/go-sev-guest/proto/sevsnp"
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LeveledQuoteProvider is an autogenerated mock type for the LeveledQuoteProvider type
|
|
||||||
type LeveledQuoteProvider struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
type LeveledQuoteProvider_Expecter struct {
|
|
||||||
mock *mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_m *LeveledQuoteProvider) EXPECT() *LeveledQuoteProvider_Expecter {
|
|
||||||
return &LeveledQuoteProvider_Expecter{mock: &_m.Mock}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRawQuoteAtLevel provides a mock function with given fields: reportData, vmpl
|
|
||||||
func (_m *LeveledQuoteProvider) GetRawQuoteAtLevel(reportData [64]byte, vmpl uint) ([]uint8, error) {
|
|
||||||
ret := _m.Called(reportData, vmpl)
|
|
||||||
|
|
||||||
if len(ret) == 0 {
|
|
||||||
panic("no return value specified for GetRawQuoteAtLevel")
|
|
||||||
}
|
|
||||||
|
|
||||||
var r0 []uint8
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(0).(func([64]byte, uint) ([]uint8, error)); ok {
|
|
||||||
return rf(reportData, vmpl)
|
|
||||||
}
|
|
||||||
if rf, ok := ret.Get(0).(func([64]byte, uint) []uint8); ok {
|
|
||||||
r0 = rf(reportData, vmpl)
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).([]uint8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rf, ok := ret.Get(1).(func([64]byte, uint) error); ok {
|
|
||||||
r1 = rf(reportData, vmpl)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeveledQuoteProvider_GetRawQuoteAtLevel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRawQuoteAtLevel'
|
|
||||||
type LeveledQuoteProvider_GetRawQuoteAtLevel_Call struct {
|
|
||||||
*mock.Call
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRawQuoteAtLevel is a helper method to define mock.On call
|
|
||||||
// - reportData [64]byte
|
|
||||||
// - vmpl uint
|
|
||||||
func (_e *LeveledQuoteProvider_Expecter) GetRawQuoteAtLevel(reportData interface{}, vmpl interface{}) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
|
||||||
return &LeveledQuoteProvider_GetRawQuoteAtLevel_Call{Call: _e.mock.On("GetRawQuoteAtLevel", reportData, vmpl)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) Run(run func(reportData [64]byte, vmpl uint)) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
|
||||||
run(args[0].([64]byte), args[1].(uint))
|
|
||||||
})
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) Return(_a0 []uint8, _a1 error) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
|
||||||
_c.Call.Return(_a0, _a1)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) RunAndReturn(run func([64]byte, uint) ([]uint8, error)) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
|
||||||
_c.Call.Return(run)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSupported provides a mock function with no fields
|
|
||||||
func (_m *LeveledQuoteProvider) IsSupported() bool {
|
|
||||||
ret := _m.Called()
|
|
||||||
|
|
||||||
if len(ret) == 0 {
|
|
||||||
panic("no return value specified for IsSupported")
|
|
||||||
}
|
|
||||||
|
|
||||||
var r0 bool
|
|
||||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
|
||||||
r0 = rf()
|
|
||||||
} else {
|
|
||||||
r0 = ret.Get(0).(bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeveledQuoteProvider_IsSupported_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSupported'
|
|
||||||
type LeveledQuoteProvider_IsSupported_Call struct {
|
|
||||||
*mock.Call
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSupported is a helper method to define mock.On call
|
|
||||||
func (_e *LeveledQuoteProvider_Expecter) IsSupported() *LeveledQuoteProvider_IsSupported_Call {
|
|
||||||
return &LeveledQuoteProvider_IsSupported_Call{Call: _e.mock.On("IsSupported")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_IsSupported_Call) Run(run func()) *LeveledQuoteProvider_IsSupported_Call {
|
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
|
||||||
run()
|
|
||||||
})
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_IsSupported_Call) Return(_a0 bool) *LeveledQuoteProvider_IsSupported_Call {
|
|
||||||
_c.Call.Return(_a0)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_IsSupported_Call) RunAndReturn(run func() bool) *LeveledQuoteProvider_IsSupported_Call {
|
|
||||||
_c.Call.Return(run)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Product provides a mock function with no fields
|
|
||||||
func (_m *LeveledQuoteProvider) Product() *sevsnp.SevProduct {
|
|
||||||
ret := _m.Called()
|
|
||||||
|
|
||||||
if len(ret) == 0 {
|
|
||||||
panic("no return value specified for Product")
|
|
||||||
}
|
|
||||||
|
|
||||||
var r0 *sevsnp.SevProduct
|
|
||||||
if rf, ok := ret.Get(0).(func() *sevsnp.SevProduct); ok {
|
|
||||||
r0 = rf()
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).(*sevsnp.SevProduct)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeveledQuoteProvider_Product_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Product'
|
|
||||||
type LeveledQuoteProvider_Product_Call struct {
|
|
||||||
*mock.Call
|
|
||||||
}
|
|
||||||
|
|
||||||
// Product is a helper method to define mock.On call
|
|
||||||
func (_e *LeveledQuoteProvider_Expecter) Product() *LeveledQuoteProvider_Product_Call {
|
|
||||||
return &LeveledQuoteProvider_Product_Call{Call: _e.mock.On("Product")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_Product_Call) Run(run func()) *LeveledQuoteProvider_Product_Call {
|
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
|
||||||
run()
|
|
||||||
})
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_Product_Call) Return(_a0 *sevsnp.SevProduct) *LeveledQuoteProvider_Product_Call {
|
|
||||||
_c.Call.Return(_a0)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_c *LeveledQuoteProvider_Product_Call) RunAndReturn(run func() *sevsnp.SevProduct) *LeveledQuoteProvider_Product_Call {
|
|
||||||
_c.Call.Return(run)
|
|
||||||
return _c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLeveledQuoteProvider creates a new instance of LeveledQuoteProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
|
||||||
// The first argument is typically a *testing.T value.
|
|
||||||
func NewLeveledQuoteProvider(t interface {
|
|
||||||
mock.TestingT
|
|
||||||
Cleanup(func())
|
|
||||||
}) *LeveledQuoteProvider {
|
|
||||||
mock := &LeveledQuoteProvider{}
|
|
||||||
mock.Mock.Test(t)
|
|
||||||
|
|
||||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
|
||||||
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
@@ -21,18 +21,16 @@ import (
|
|||||||
"github.com/google/go-sev-guest/verify"
|
"github.com/google/go-sev-guest/verify"
|
||||||
"github.com/google/go-sev-guest/verify/trust"
|
"github.com/google/go-sev-guest/verify/trust"
|
||||||
"github.com/google/logger"
|
"github.com/google/logger"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cocosDirectory = ".cocos"
|
cocosDirectory = ".cocos"
|
||||||
caBundleName = "ask_ark.pem"
|
caBundleName = "ask_ark.pem"
|
||||||
attestationReportSize = 0x4A0
|
Nonce = 64
|
||||||
Nonce = 64
|
sevProductNameMilan = "Milan"
|
||||||
sevProductNameMilan = "Milan"
|
sevProductNameGenoa = "Genoa"
|
||||||
sevProductNameGenoa = "Genoa"
|
|
||||||
sevVMPL = 2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -87,15 +85,7 @@ func verifyReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Policy.Product == nil {
|
if cfg.Policy.Product == nil {
|
||||||
productName := sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN
|
productName := GetProductName(cfg.RootOfTrust.ProductLine)
|
||||||
switch cfg.RootOfTrust.ProductLine {
|
|
||||||
case sevProductNameMilan:
|
|
||||||
productName = sevsnp.SevProduct_SEV_PRODUCT_MILAN
|
|
||||||
case sevProductNameGenoa:
|
|
||||||
productName = sevsnp.SevProduct_SEV_PRODUCT_GENOA
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if productName == sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN {
|
if productName == sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN {
|
||||||
return errProductLine
|
return errProductLine
|
||||||
}
|
}
|
||||||
@@ -127,7 +117,7 @@ func verifyReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
|||||||
func validateReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
func validateReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
||||||
opts, err := validate.PolicyToOptions(cfg.Policy)
|
opts, err := validate.PolicyToOptions(cfg.Policy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get policy for validation %v", errors.Wrap(errAttVerification, err))
|
return fmt.Errorf("failed to get policy for validation: %v", errors.Wrap(errAttVerification, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = validate.SnpAttestation(attestationPB, opts); err != nil {
|
if err = validate.SnpAttestation(attestationPB, opts); err != nil {
|
||||||
@@ -142,7 +132,7 @@ func GetLeveledQuoteProvider() (client.LeveledQuoteProvider, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []byte) error {
|
func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []byte) error {
|
||||||
config, err := copyConfig(config.AttestationPolicy.Config)
|
config, err := copyConfig(attestation.AttestationPolicy.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(fmt.Errorf("failed to create a copy of attestation policy"), err)
|
return errors.Wrap(fmt.Errorf("failed to create a copy of attestation policy"), err)
|
||||||
}
|
}
|
||||||
@@ -150,7 +140,11 @@ func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []
|
|||||||
// Certificate chain is populated based on the extra data that is appended to the SEV-SNP attestation report.
|
// Certificate chain is populated based on the extra data that is appended to the SEV-SNP attestation report.
|
||||||
// This data is not part of the attestation report and it will be ignored.
|
// This data is not part of the attestation report and it will be ignored.
|
||||||
attestationPB.CertificateChain = nil
|
attestationPB.CertificateChain = nil
|
||||||
config.Policy.ReportData = reportData[:]
|
|
||||||
|
if len(reportData) != 0 {
|
||||||
|
config.Policy.ReportData = reportData[:]
|
||||||
|
}
|
||||||
|
|
||||||
return VerifyAndValidate(attestationPB, config)
|
return VerifyAndValidate(attestationPB, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +162,7 @@ func VerifyAndValidate(attestationPB *sevsnp.Attestation, cfg *check.Config) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
func FetchAttestation(reportDataSlice []byte, vmpl uint) ([]byte, error) {
|
||||||
var reportData [Nonce]byte
|
var reportData [Nonce]byte
|
||||||
|
|
||||||
qp, err := GetLeveledQuoteProvider()
|
qp, err := GetLeveledQuoteProvider()
|
||||||
@@ -181,10 +175,21 @@ func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
copy(reportData[:], reportDataSlice)
|
copy(reportData[:], reportDataSlice)
|
||||||
|
|
||||||
rawQuote, err := qp.GetRawQuoteAtLevel(reportData, sevVMPL)
|
rawQuote, err := qp.GetRawQuoteAtLevel(reportData, vmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, fmt.Errorf("failed to get raw quote")
|
return []byte{}, fmt.Errorf("failed to get raw quote")
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawQuote, nil
|
return rawQuote, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetProductName(product string) sevsnp.SevProduct_SevProductName {
|
||||||
|
switch product {
|
||||||
|
case sevProductNameMilan:
|
||||||
|
return sevsnp.SevProduct_SEV_PRODUCT_MILAN
|
||||||
|
case sevProductNameGenoa:
|
||||||
|
return sevsnp.SevProduct_SEV_PRODUCT_GENOA
|
||||||
|
default:
|
||||||
|
return sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -185,8 +185,8 @@ func prepVerifyAttReport(t *testing.T) (*sevsnp.Attestation, []byte) {
|
|||||||
file, err := os.ReadFile("../../../attestation.bin")
|
file, err := os.ReadFile("../../../attestation.bin")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if len(file) < attestationReportSize {
|
if len(file) < abi.ReportSize {
|
||||||
file = append(file, make([]byte, attestationReportSize-len(file))...)
|
file = append(file, make([]byte, abi.ReportSize-len(file))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, err := abi.ReportCertsToProto(file)
|
rr, err := abi.ReportCertsToProto(file)
|
||||||
|
|||||||
+121
-87
@@ -8,7 +8,6 @@ import (
|
|||||||
"crypto"
|
"crypto"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/x509"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -17,18 +16,22 @@ import (
|
|||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
"github.com/google/go-sev-guest/abi"
|
"github.com/google/go-sev-guest/abi"
|
||||||
|
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||||
"github.com/google/go-tpm-tools/client"
|
"github.com/google/go-tpm-tools/client"
|
||||||
"github.com/google/go-tpm-tools/proto/attest"
|
"github.com/google/go-tpm-tools/proto/attest"
|
||||||
"github.com/google/go-tpm-tools/proto/tpm"
|
ptpm "github.com/google/go-tpm-tools/proto/tpm"
|
||||||
"github.com/google/go-tpm-tools/server"
|
"github.com/google/go-tpm-tools/server"
|
||||||
"github.com/google/go-tpm/legacy/tpm2"
|
"github.com/google/go-tpm/legacy/tpm2"
|
||||||
"github.com/google/go-tpm/tpmutil"
|
"github.com/google/go-tpm/tpmutil"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
"google.golang.org/protobuf/encoding/prototext"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ attestation.Provider = (*provider)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
eventLog = "/sys/kernel/security/tpm0/binary_bios_measurements"
|
eventLog = "/sys/kernel/security/tpm0/binary_bios_measurements"
|
||||||
Nonce = 32
|
Nonce = 32
|
||||||
@@ -41,24 +44,23 @@ const (
|
|||||||
var (
|
var (
|
||||||
ExternalTPM io.ReadWriteCloser
|
ExternalTPM io.ReadWriteCloser
|
||||||
ErrNoHashAlgo = errors.New("hash algo is not supported")
|
ErrNoHashAlgo = errors.New("hash algo is not supported")
|
||||||
|
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
|
||||||
)
|
)
|
||||||
|
|
||||||
type VtpmAttest func(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error)
|
type tpm struct {
|
||||||
|
|
||||||
type tpmWrapper struct {
|
|
||||||
io.ReadWriteCloser
|
io.ReadWriteCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (et tpmWrapper) EventLog() ([]byte, error) {
|
func (et tpm) EventLog() ([]byte, error) {
|
||||||
return os.ReadFile(eventLog)
|
return os.ReadFile(eventLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
func OpenTpm() (io.ReadWriteCloser, error) {
|
func OpenTpm() (io.ReadWriteCloser, error) {
|
||||||
if ExternalTPM != nil {
|
if ExternalTPM != nil {
|
||||||
return tpmWrapper{ExternalTPM}, nil
|
return tpm{ExternalTPM}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tw := tpmWrapper{}
|
tw := tpm{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
tw.ReadWriteCloser, err = tpm2.OpenTPM("/dev/tpmrm0")
|
tw.ReadWriteCloser, err = tpm2.OpenTPM("/dev/tpmrm0")
|
||||||
@@ -89,14 +91,65 @@ func ExtendPCR(pcrIndex int, value []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error) {
|
type provider struct {
|
||||||
attestation, err := fetchVTPMQuote(vTPMNonce)
|
pubKey []byte
|
||||||
|
teeAttestaion bool
|
||||||
|
vmpl uint
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(pubKey []byte, teeAttestation bool, vmpl uint, writer io.Writer) attestation.Provider {
|
||||||
|
return &provider{
|
||||||
|
pubKey: pubKey,
|
||||||
|
teeAttestaion: teeAttestation,
|
||||||
|
vmpl: vmpl,
|
||||||
|
writer: writer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||||
|
return Attest(teeNonce, vTpmNonce, v.teeAttestaion, v.vmpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||||
|
return quoteprovider.FetchAttestation(teeNonce, v.vmpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||||
|
quote, err := FetchQuote(vTpmNonce)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, errors.Wrap(ErrFetchQuote, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto.Marshal(quote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||||
|
attestReport, err := abi.ReportToProto(report)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
attestationReport := sevsnp.Attestation{Report: attestReport, CertificateChain: nil}
|
||||||
|
return quoteprovider.VerifyAttestationReportTLS(&attestationReport, teeNonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||||
|
return VerifyQuote(report, v.pubKey, vTpmNonce, v.writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||||
|
return VTPMVerify(report, v.pubKey, teeNonce, vTpmNonce, v.writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([]byte, error) {
|
||||||
|
attestation, err := FetchQuote(vTPMNonce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if teeAttestaion {
|
if teeAttestaion {
|
||||||
attestation, err = addTEEAttestation(attestation, teeNonce)
|
err = addTEEAttestation(attestation, teeNonce, vmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return []byte{}, err
|
||||||
}
|
}
|
||||||
@@ -105,26 +158,26 @@ func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, erro
|
|||||||
return marshalQuote(attestation)
|
return marshalQuote(attestation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchATLSQuote(pubKey, teeNonce, vTPMNonce []byte) ([]byte, error) {
|
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte, writer io.Writer) error {
|
||||||
attestation, err := fetchVTPMQuote(vTPMNonce)
|
if err := VerifyQuote(quote, pubKeyTLS, vtpmNonce, writer); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("failed to verify vTPM quote: %v", err)
|
||||||
return []byte{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reportData, err := createTEEAttestationReportNonce(pubKey, attestation.GetAkPub(), teeNonce)
|
attestation := &attest.Attestation{}
|
||||||
|
|
||||||
|
err := proto.Unmarshal(quote, attestation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []byte{}, err
|
return errors.Wrap(fmt.Errorf("failed to unmarshal quote"), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
attestation, err = addTEEAttestation(attestation, reportData)
|
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), teeNonce); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("failed to verify TEE attestation report: %v", err)
|
||||||
return []byte{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return marshalQuote(attestation)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte) error {
|
func VerifyQuote(quote []byte, pubKeyTLS []byte, vtpmNonce []byte, writer io.Writer) error {
|
||||||
attestation := &attest.Attestation{}
|
attestation := &attest.Attestation{}
|
||||||
|
|
||||||
err := proto.Unmarshal(quote, attestation)
|
err := proto.Unmarshal(quote, attestation)
|
||||||
@@ -143,16 +196,7 @@ func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byt
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
reportData, err := createTEEAttestationReportNonce(pubKeyTLS, ak, teeNonce)
|
ms, err := server.VerifyAttestation(attestation, server.VerifyOpts{Nonce: vtpmNonce, TrustedAKs: []crypto.PublicKey{cryptoPub}})
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(fmt.Errorf("failed to create TEE attestation report nonce"), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), reportData); err != nil {
|
|
||||||
return fmt.Errorf("failed to verify TEE attestation report: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = server.VerifyAttestation(attestation, server.VerifyOpts{Nonce: vtpmNonce, TrustedAKs: []crypto.PublicKey{cryptoPub}})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(fmt.Errorf("failed to verify attestation"), err)
|
return errors.Wrap(fmt.Errorf("failed to verify attestation"), err)
|
||||||
}
|
}
|
||||||
@@ -163,44 +207,22 @@ func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byt
|
|||||||
return fmt.Errorf("PCR values do not match expected PCR values: %w", err)
|
return fmt.Errorf("PCR values do not match expected PCR values: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if writer != nil {
|
||||||
|
marshalOptions := prototext.MarshalOptions{Multiline: true, EmitASCII: true}
|
||||||
|
|
||||||
|
out, err := marshalOptions.Marshal(ms)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := writer.Write(out); err != nil {
|
||||||
|
return fmt.Errorf("failed to write verified attestation report: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmptyAttest is a dummy attestation function that returns an empty attestation report.
|
|
||||||
func EmptyAttest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error) {
|
|
||||||
return []byte{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func publicKeyToBytes(pubKey interface{}) ([]byte, error) {
|
|
||||||
derBytes, err := x509.MarshalPKIXPublicKey(pubKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return derBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTEEAttestationReportNonce(pubKeyTLS []byte, ak []byte, nonce []byte) ([]byte, error) {
|
|
||||||
pub, err := tpm2.DecodePublic(ak)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cryptoPub, err := pub.Key()
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKeyBytes, err := publicKeyToBytes(cryptoPub)
|
|
||||||
if err != nil {
|
|
||||||
return []byte{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reportData := append(append(pubKeyTLS, pubKeyBytes...), nonce...)
|
|
||||||
hash := sha3.Sum512(reportData)
|
|
||||||
|
|
||||||
return hash[:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func marshalQuote(attestation *attest.Attestation) ([]byte, error) {
|
func marshalQuote(attestation *attest.Attestation) ([]byte, error) {
|
||||||
out, err := proto.Marshal(attestation)
|
out, err := proto.Marshal(attestation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -210,7 +232,7 @@ func marshalQuote(attestation *attest.Attestation) ([]byte, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchVTPMQuote(nonce []byte) (*attest.Attestation, error) {
|
func FetchQuote(nonce []byte) (*attest.Attestation, error) {
|
||||||
rwc, err := OpenTpm()
|
rwc, err := OpenTpm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -241,46 +263,54 @@ func fetchVTPMQuote(nonce []byte) (*attest.Attestation, error) {
|
|||||||
return attestation, nil
|
return attestation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTEEAttestation(attestation *attest.Attestation, nonce []byte) (*attest.Attestation, error) {
|
func addTEEAttestation(attestation *attest.Attestation, nonce []byte, vmpl uint) error {
|
||||||
rawTeeAttestation, err := quoteprovider.FetchAttestation(nonce)
|
rawTeeAttestation, err := quoteprovider.FetchAttestation(nonce, vmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return attestation, fmt.Errorf("failed to fetch TEE attestation report: %v", err)
|
return fmt.Errorf("failed to fetch TEE attestation report: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
extReport, err := abi.ReportCertsToProto(rawTeeAttestation)
|
extReport, err := abi.ReportCertsToProto(rawTeeAttestation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return attestation, errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||||
}
|
}
|
||||||
attestation.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
attestation.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
||||||
SevSnpAttestation: extReport,
|
SevSnpAttestation: extReport,
|
||||||
}
|
}
|
||||||
|
|
||||||
return attestation, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []byte) error {
|
func checkExpectedPCRValues(attQuote *attest.Attestation, ePcr256, ePcr384 []byte) error {
|
||||||
quotes := attestation.GetQuotes()
|
quotes := attQuote.GetQuotes()
|
||||||
for i := range quotes {
|
for i := range quotes {
|
||||||
quote := quotes[i]
|
quote := quotes[i]
|
||||||
var pcrMap map[string]string
|
var pcrMap map[string]string
|
||||||
var pcr15 []byte
|
var pcr15 []byte
|
||||||
switch quote.Pcrs.Hash {
|
switch quote.Pcrs.Hash {
|
||||||
case tpm.HashAlgo_SHA256:
|
case ptpm.HashAlgo_SHA256:
|
||||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha256
|
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha256
|
||||||
pcr15 = ePcr256
|
if ePcr256 == nil {
|
||||||
case tpm.HashAlgo_SHA384:
|
pcr15 = make([]byte, 32)
|
||||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha384
|
} else {
|
||||||
pcr15 = ePcr384
|
pcr15 = ePcr256
|
||||||
case tpm.HashAlgo_SHA1:
|
}
|
||||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha1
|
case ptpm.HashAlgo_SHA384:
|
||||||
|
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha384
|
||||||
|
if ePcr384 == nil {
|
||||||
|
pcr15 = make([]byte, 48)
|
||||||
|
} else {
|
||||||
|
pcr15 = ePcr384
|
||||||
|
}
|
||||||
|
case ptpm.HashAlgo_SHA1:
|
||||||
|
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha1
|
||||||
pcr15 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
pcr15 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
default:
|
default:
|
||||||
return errors.Wrap(ErrNoHashAlgo, fmt.Errorf("algo: %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)]))
|
return errors.Wrap(ErrNoHashAlgo, fmt.Errorf("algo: %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pcr15Index := uint32(15)
|
pcr15Index := uint32(15)
|
||||||
if !bytes.Equal(quote.Pcrs.Pcrs[pcr15Index], pcr15) {
|
if !bytes.Equal(quote.Pcrs.Pcrs[pcr15Index], pcr15) {
|
||||||
return fmt.Errorf("for algo %s PCR[15] expected %s but found %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)], hex.EncodeToString(pcr15), hex.EncodeToString(quote.Pcrs.Pcrs[pcr15Index]))
|
return fmt.Errorf("for algo %s PCR[15] expected %s but found %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)], hex.EncodeToString(pcr15), hex.EncodeToString(quote.Pcrs.Pcrs[pcr15Index]))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v := range pcrMap {
|
for i, v := range pcrMap {
|
||||||
@@ -293,7 +323,7 @@ func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []
|
|||||||
return errors.Wrap(fmt.Errorf("error converting PCR value to byte"), err)
|
return errors.Wrap(fmt.Errorf("error converting PCR value to byte"), err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(quote.Pcrs.Pcrs[uint32(index)], value) {
|
if !bytes.Equal(quote.Pcrs.Pcrs[uint32(index)], value) {
|
||||||
return fmt.Errorf("for algo %s PCR[%d] expected %s but found %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)], index, hex.EncodeToString(value), hex.EncodeToString(quote.Pcrs.Pcrs[uint32(index)]))
|
return fmt.Errorf("for algo %s PCR[%d] expected %s but found %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)], index, hex.EncodeToString(value), hex.EncodeToString(quote.Pcrs.Pcrs[uint32(index)]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,6 +332,10 @@ func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []
|
|||||||
|
|
||||||
// Return SHA256 and SHA384 values of the input public key.
|
// Return SHA256 and SHA384 values of the input public key.
|
||||||
func calculatePCRTLSKey(pubKey []byte) ([]byte, []byte) {
|
func calculatePCRTLSKey(pubKey []byte) ([]byte, []byte) {
|
||||||
|
if len(pubKey) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
init256 := make([]byte, Hash256)
|
init256 := make([]byte, Hash256)
|
||||||
init384 := make([]byte, Hash384)
|
init384 := make([]byte, Hash384)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||||
"github.com/ultravioletrs/cocos/agent/mocks"
|
"github.com/ultravioletrs/cocos/agent/mocks"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/health"
|
"google.golang.org/grpc/health"
|
||||||
@@ -113,7 +113,7 @@ func TestAgentClientIntegration(t *testing.T) {
|
|||||||
},
|
},
|
||||||
AttestedTLS: true,
|
AttestedTLS: true,
|
||||||
},
|
},
|
||||||
err: config.ErrAttestationPolicyMissing,
|
err: attestation.ErrAttestationPolicyMissing,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ import (
|
|||||||
|
|
||||||
"github.com/absmach/magistrala/pkg/errors"
|
"github.com/absmach/magistrala/pkg/errors"
|
||||||
"github.com/ultravioletrs/cocos/pkg/atls"
|
"github.com/ultravioletrs/cocos/pkg/atls"
|
||||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupATLS(cfg AgentClientConfig) (credentials.TransportCredentials, error) {
|
func setupATLS(cfg AgentClientConfig) (credentials.TransportCredentials, error) {
|
||||||
err := config.ReadAttestationPolicy(cfg.AttestationPolicy, &config.AttestationPolicy)
|
err := attestation.ReadAttestationPolicy(cfg.AttestationPolicy, &attestation.AttestationPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(fmt.Errorf("failed to read Attestation Policy"), err)
|
return nil, errors.Wrap(fmt.Errorf("failed to read Attestation Policy"), err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
"github.com/google/go-sev-guest/proto/check"
|
"github.com/google/go-sev-guest/proto/check"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
att "github.com/ultravioletrs/cocos/pkg/attestation"
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
@@ -221,25 +221,25 @@ func TestReadAttestationPolicy(t *testing.T) {
|
|||||||
name: "Invalid JSON",
|
name: "Invalid JSON",
|
||||||
manifestPath: "invalid_manifest.json",
|
manifestPath: "invalid_manifest.json",
|
||||||
fileContent: invalidJSON,
|
fileContent: invalidJSON,
|
||||||
err: att.ErrAttestationPolicyDecode,
|
err: attestation.ErrAttestationPolicyDecode,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Non-existent file",
|
name: "Non-existent file",
|
||||||
manifestPath: "nonexistent.json",
|
manifestPath: "nonexistent.json",
|
||||||
fileContent: "",
|
fileContent: "",
|
||||||
err: att.ErrAttestationPolicyOpen,
|
err: attestation.ErrAttestationPolicyOpen,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Empty manifest path",
|
name: "Empty manifest path",
|
||||||
manifestPath: "",
|
manifestPath: "",
|
||||||
fileContent: "",
|
fileContent: "",
|
||||||
err: att.ErrAttestationPolicyMissing,
|
err: attestation.ErrAttestationPolicyMissing,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid JSON PCR",
|
name: "Invalid JSON PCR",
|
||||||
manifestPath: "invalid_manifest.json",
|
manifestPath: "invalid_manifest.json",
|
||||||
fileContent: invalidJSONPCR,
|
fileContent: invalidJSONPCR,
|
||||||
err: att.ErrAttestationPolicyDecode,
|
err: attestation.ErrAttestationPolicyDecode,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +251,8 @@ func TestReadAttestationPolicy(t *testing.T) {
|
|||||||
defer os.Remove(tt.manifestPath)
|
defer os.Remove(tt.manifestPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := att.Config{Config: &check.Config{}, PcrConfig: &att.PcrConfig{}}
|
config := attestation.Config{Config: &check.Config{}, PcrConfig: &attestation.PcrConfig{}}
|
||||||
err := att.ReadAttestationPolicy(tt.manifestPath, &config)
|
err := attestation.ReadAttestationPolicy(tt.manifestPath, &config)
|
||||||
|
|
||||||
assert.True(t, errors.Contains(err, tt.err), fmt.Sprintf("expected error %v, got %v", tt.err, err))
|
assert.True(t, errors.Contains(err, tt.err), fmt.Sprintf("expected error %v, got %v", tt.err, err))
|
||||||
if tt.err == nil {
|
if tt.err == nil {
|
||||||
|
|||||||
+10
-10
@@ -27,16 +27,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AttestationReportSize = 0x4A0
|
WithATLS = "with aTLS"
|
||||||
WithATLS = "with aTLS"
|
WithTLS = "with TLS"
|
||||||
WithTLS = "with TLS"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errGrpcConnect = errors.New("failed to connect to grpc server")
|
errGrpcConnect = errors.New("failed to connect to grpc server")
|
||||||
errGrpcClose = errors.New("failed to close grpc connection")
|
errGrpcClose = errors.New("failed to close grpc connection")
|
||||||
errCertificateParse = errors.New("failed to parse x509 certificate")
|
errCertificateParse = errors.New("failed to parse x509 certificate")
|
||||||
errAttVerification = errors.New("certificat is not sefl signed")
|
errAttVerification = errors.New("certificat is not self signed")
|
||||||
errFailedToLoadClientCertKey = errors.New("failed to load client certificate and key")
|
errFailedToLoadClientCertKey = errors.New("failed to load client certificate and key")
|
||||||
errFailedToLoadRootCA = errors.New("failed to load root ca file")
|
errFailedToLoadRootCA = errors.New("failed to load root ca file")
|
||||||
)
|
)
|
||||||
@@ -57,6 +56,7 @@ type AgentClientConfig struct {
|
|||||||
BaseConfig
|
BaseConfig
|
||||||
AttestationPolicy string `env:"ATTESTATION_POLICY" envDefault:""`
|
AttestationPolicy string `env:"ATTESTATION_POLICY" envDefault:""`
|
||||||
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
|
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
|
||||||
|
ProductName string `env:"PRODUCT_NAME" envDefault:"Milan"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ManagerClientConfig struct {
|
type ManagerClientConfig struct {
|
||||||
@@ -147,7 +147,7 @@ func connect(cfg ClientConfiguration) (*grpc.ClientConn, security, error) {
|
|||||||
secure = withaTLS
|
secure = withaTLS
|
||||||
} else {
|
} else {
|
||||||
conf := cfg.GetBaseConfig()
|
conf := cfg.GetBaseConfig()
|
||||||
transportCreds, err, sec := loadTLSConfig(conf.ServerCAFile, conf.ClientCert, conf.ClientKey)
|
transportCreds, sec, err := loadTLSConfig(conf.ServerCAFile, conf.ClientCert, conf.ClientKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, secure, err
|
return nil, secure, err
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ func connect(cfg ClientConfiguration) (*grpc.ClientConn, security, error) {
|
|||||||
return conn, secure, nil
|
return conn, secure, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.TransportCredentials, error, security) {
|
func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.TransportCredentials, security, error) {
|
||||||
tlsConfig := &tls.Config{}
|
tlsConfig := &tls.Config{}
|
||||||
secure := withoutTLS
|
secure := withoutTLS
|
||||||
tc := insecure.NewCredentials()
|
tc := insecure.NewCredentials()
|
||||||
@@ -170,12 +170,12 @@ func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.Tran
|
|||||||
if serverCAFile != "" {
|
if serverCAFile != "" {
|
||||||
rootCA, err := os.ReadFile(serverCAFile)
|
rootCA, err := os.ReadFile(serverCAFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(errFailedToLoadRootCA, err), secure
|
return nil, secure, errors.Wrap(errFailedToLoadRootCA, err)
|
||||||
}
|
}
|
||||||
if len(rootCA) > 0 {
|
if len(rootCA) > 0 {
|
||||||
capool := x509.NewCertPool()
|
capool := x509.NewCertPool()
|
||||||
if !capool.AppendCertsFromPEM(rootCA) {
|
if !capool.AppendCertsFromPEM(rootCA) {
|
||||||
return nil, fmt.Errorf("failed to append root ca to tls.Config"), secure
|
return nil, secure, fmt.Errorf("failed to append root ca to tls.Config")
|
||||||
}
|
}
|
||||||
tlsConfig.RootCAs = capool
|
tlsConfig.RootCAs = capool
|
||||||
secure = withTLS
|
secure = withTLS
|
||||||
@@ -186,12 +186,12 @@ func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.Tran
|
|||||||
if clientCert != "" || clientKey != "" {
|
if clientCert != "" || clientKey != "" {
|
||||||
certificate, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
certificate, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(errFailedToLoadClientCertKey, err), secure
|
return nil, secure, errors.Wrap(errFailedToLoadClientCertKey, err)
|
||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{certificate}
|
tlsConfig.Certificates = []tls.Certificate{certificate}
|
||||||
secure = withmTLS
|
secure = withmTLS
|
||||||
tc = credentials.NewTLS(tlsConfig)
|
tc = credentials.NewTLS(tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tc, nil, secure
|
return tc, secure, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-6
@@ -15,10 +15,20 @@ The service is configured using the environment variables from the following tab
|
|||||||
|
|
||||||
## Running
|
## Running
|
||||||
```shell
|
```shell
|
||||||
go run main.go <algo_path> <public_key_path> <attested_tls_bool> <dataset(s)_path>
|
Usage of tests/cvms/main.go:
|
||||||
```
|
-algo-path string
|
||||||
|
Path to the algorithm
|
||||||
|
-attested-tls-bool string
|
||||||
|
Should aTLS be used, must be 'true' or 'false'
|
||||||
|
-ca-url string
|
||||||
|
URL for certificate authority, optional flag that can only be used if aTLS is enabled
|
||||||
|
-cvm-id string
|
||||||
|
UUID for a CVM, optional flag that can only be used if aTLS is enabled
|
||||||
|
-data-paths string
|
||||||
|
Paths to data sources, list of string separated with commas
|
||||||
|
-public-key-path string
|
||||||
|
Path to the public key file
|
||||||
|
|
||||||
- `algo_path`: Path to the algorithm file (python file,docker image file, wasm, compiled binary) \
|
# Example
|
||||||
- `public_key_path`: Path to the public key file (PEM format) \
|
go run ./tests/cvms/main.go -algo-path <alog_path> -attested-tls-bool false -data-paths <data_paths> -public-key-path <public_key_path>
|
||||||
- `attested_tls_bool`: Boolean flag to enable/disable attested TLS (true/false) \
|
```
|
||||||
- `dataset(s)_path`: Path to one or more dataset files.
|
|
||||||
|
|||||||
+7
-7
@@ -106,8 +106,8 @@ func main() {
|
|||||||
flagSet.StringVar(&pubKeyFile, "public-key-path", "", "Path to the public key file")
|
flagSet.StringVar(&pubKeyFile, "public-key-path", "", "Path to the public key file")
|
||||||
flagSet.StringVar(&attestedTLSString, "attested-tls-bool", "", "Should aTLS be used, must be 'true' or 'false'")
|
flagSet.StringVar(&attestedTLSString, "attested-tls-bool", "", "Should aTLS be used, must be 'true' or 'false'")
|
||||||
flagSet.StringVar(&dataPathString, "data-paths", "", "Paths to data sources, list of string separated with commas")
|
flagSet.StringVar(&dataPathString, "data-paths", "", "Paths to data sources, list of string separated with commas")
|
||||||
flagSet.StringVar(&caUrl, "ca-url", "", "URL for certificate authority, must be specified if aTLS is used")
|
flagSet.StringVar(&caUrl, "ca-url", "", "URL for certificate authority, optional flag that can only be used if aTLS is enabled")
|
||||||
flagSet.StringVar(&cvmId, "cvm-id", "", "UUID for a CVM, must be specified if aTLS is used")
|
flagSet.StringVar(&cvmId, "cvm-id", "", "UUID for a CVM, optional flag that can only be used if aTLS is enabled")
|
||||||
|
|
||||||
flagSetParseError := flagSet.Parse(os.Args[1:])
|
flagSetParseError := flagSet.Parse(os.Args[1:])
|
||||||
if flagSetParseError != nil {
|
if flagSetParseError != nil {
|
||||||
@@ -145,13 +145,13 @@ func main() {
|
|||||||
dataPaths = strings.Split(dataPathString, ",")
|
dataPaths = strings.Split(dataPathString, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && attestedTLS && caUrl == "" {
|
if err == nil && caUrl != "" && !attestedTLS {
|
||||||
parsingErrorString.WriteString("CA URL is required if attested TLS is used\n")
|
parsingErrorString.WriteString("CA URL is only available with attested TLS\n")
|
||||||
parsingError = true
|
parsingError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && attestedTLS && cvmId == "" {
|
if err == nil && cvmId != "" && !attestedTLS {
|
||||||
parsingErrorString.WriteString("CVM UUID is required if attested TLS is used\n")
|
parsingErrorString.WriteString("CVM UUID is only available with attested TLS\n")
|
||||||
parsingError = true
|
parsingError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, nil, nil, caUrl, cvmId)
|
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, nil, caUrl, cvmId)
|
||||||
|
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
return gs.Start()
|
return gs.Start()
|
||||||
|
|||||||
Reference in New Issue
Block a user