NOISSUE - Introduce a dedicated attestation service and refactor agent to use its gRPC client (#558)

* feat: introduce a dedicated attestation service and refactor agent to use its gRPC client

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Source attestation-service from GitHub, updating its build and installation process.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* fix: update protoc version to 33.1 in CI workflow

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: Update Go build tag syntax, octal literals, and simplify agent attestation logic.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* chore: update igvmmeasure script's subdirectory path to tools/igvmmeasure

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: rename AttestationService RPC methods from `Get` to `Fetch` and update corresponding service implementation.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: rename attestation client methods from `GetX` to `FetchX`

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

---------

Signed-off-by: Sammy Oina <sammyoina@gmail.com>
This commit is contained in:
Sammy Kerata Oina
2025-12-17 16:07:11 +03:00
committed by GitHub
parent 3f06971976
commit c422afe0a6
35 changed files with 1024 additions and 132 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
- name: Set up protoc
run: |
PROTOC_VERSION=29.0
PROTOC_VERSION=33.1
PROTOC_GEN_VERSION=v1.36.8
PROTOC_GRPC_VERSION=v1.5.1
+2 -1
View File
@@ -1,5 +1,5 @@
BUILD_DIR = build
SERVICES = manager agent cli
SERVICES = manager agent cli attestation-service
ATTESTATION_POLICY = attestation_policy
CGO_ENABLED ?= 0
GOARCH ?= amd64
@@ -40,6 +40,7 @@ protoc:
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative manager/manager.proto
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/events/events.proto
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/cvms/cvms.proto
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative internal/proto/attestation/v1/attestation.proto
mocks:
mockery --config ./.mockery.yml
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v5.29.0
// protoc v6.33.1
// source: agent/agent.proto
package agent
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.29.0
// - protoc v6.33.1
// source: agent/agent.proto
package agent
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v5.29.0
// protoc v6.33.1
// source: agent/cvms/cvms.proto
package cvms
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.29.0
// - protoc v6.33.1
// source: agent/cvms/cvms.proto
package cvms
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v5.29.0
// protoc v6.33.1
// source: agent/events/events.proto
package events
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package agent
import (
"context"
"github.com/stretchr/testify/mock"
"github.com/ultravioletrs/cocos/pkg/attestation"
)
type MockAttestationClient struct {
mock.Mock
}
func (m *MockAttestationClient) GetAttestation(ctx context.Context, reportData [64]byte, nonce [32]byte, attType attestation.PlatformType) ([]byte, error) {
args := m.Called(ctx, reportData, nonce, attType)
return args.Get(0).([]byte), args.Error(1)
}
func (m *MockAttestationClient) GetAzureToken(ctx context.Context, nonce [32]byte) ([]byte, error) {
args := m.Called(ctx, nonce)
return args.Get(0).([]byte), args.Error(1)
}
func (m *MockAttestationClient) Close() error {
args := m.Called()
return args.Error(0)
}
+25 -45
View File
@@ -26,6 +26,7 @@ import (
"github.com/ultravioletrs/cocos/pkg/attestation"
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
attestation_client "github.com/ultravioletrs/cocos/pkg/clients/grpc/attestation"
"golang.org/x/crypto/sha3"
)
@@ -128,33 +129,33 @@ type Service interface {
}
type agentService struct {
mu sync.Mutex
computation Computation // Holds the current computation request details.
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
result []byte // Stores the result of the computation.
sm statemachine.StateMachine // Manages the state transitions of the agent service.
runError error // Stores any error encountered during the computation run.
eventSvc events.Service // Service for publishing events related to computation.
provider attestation.Provider // Provider for generating attestation quotes.
logger *slog.Logger // Logger for the agent service.
resultsConsumed bool // Indicates if the results have been consumed.
cancel context.CancelFunc // Cancels the computation context.
vmpl int // VMPL at which the Agent is running.
mu sync.Mutex
computation Computation // Holds the current computation request details.
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
result []byte // Stores the result of the computation.
sm statemachine.StateMachine // Manages the state transitions of the agent service.
runError error // Stores any error encountered during the computation run.
eventSvc events.Service // Service for publishing events related to computation.
attestationClient attestation_client.Client // Client for attestation service.
logger *slog.Logger // Logger for the agent service.
resultsConsumed bool // Indicates if the results have been consumed.
cancel context.CancelFunc // Cancels the computation context.
vmpl int // VMPL at which the Agent is running.
}
var _ Service = (*agentService)(nil)
// New instantiates the agent service implementation.
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, provider attestation.Provider, vmlp int) Service {
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, attestationClient attestation_client.Client, vmlp int) Service {
sm := statemachine.NewStateMachine(Idle)
ctx, cancel := context.WithCancel(ctx)
svc := &agentService{
sm: sm,
eventSvc: eventSvc,
provider: provider,
logger: logger,
cancel: cancel,
vmpl: vmlp,
sm: sm,
eventSvc: eventSvc,
attestationClient: attestationClient,
logger: logger,
cancel: cancel,
vmpl: vmlp,
}
transitions := []statemachine.Transition{
@@ -435,36 +436,15 @@ func (as *agentService) Result(ctx context.Context) ([]byte, error) {
}
func (as *agentService) Attestation(ctx context.Context, reportData [quoteprovider.Nonce]byte, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error) {
switch attType {
case attestation.SNP, attestation.TDX:
rawQuote, err := as.provider.TeeAttestation(reportData[:])
if err != nil {
return []byte{}, errors.Wrap(ErrAttestationFailed, err)
}
return rawQuote, nil
case attestation.VTPM:
vTPMQuote, err := as.provider.VTpmAttestation(nonce[:])
if err != nil {
return []byte{}, errors.Wrap(ErrAttestationVTpmFailed, err)
}
return vTPMQuote, nil
case attestation.SNPvTPM:
vTPMQuote, err := as.provider.Attestation(reportData[:], nonce[:])
if err != nil {
return []byte{}, errors.Wrap(ErrAttestationVTpmFailed, err)
}
return vTPMQuote, nil
default:
return []byte{}, ErrAttestationType
rawQuote, err := as.attestationClient.GetAttestation(ctx, reportData, nonce, attType)
if err != nil {
return []byte{}, errors.Wrap(ErrAttestationFailed, err)
}
return rawQuote, nil
}
func (as *agentService) AzureAttestationToken(ctx context.Context, nonce [vtpm.Nonce]byte) ([]byte, error) {
if attestation.CCPlatform() != attestation.Azure {
return []byte{}, ErrAttestationType
}
token, err := as.provider.AzureAttestationToken(nonce[:])
token, err := as.attestationClient.GetAzureToken(ctx, nonce)
if err != nil {
return []byte{}, err
}
+35 -30
View File
@@ -24,7 +24,6 @@ import (
"github.com/ultravioletrs/cocos/agent/statemachine"
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/vtpm"
"golang.org/x/crypto/sha3"
@@ -123,7 +122,8 @@ func TestAlgo(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
client := new(MockAttestationClient)
svc := New(ctx, mglog.NewMock(), events, client, 0)
err := svc.InitComputation(ctx, testComputation(t))
require.NoError(t, err)
@@ -216,7 +216,8 @@ func TestData(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
client := new(MockAttestationClient)
svc := New(ctx, mglog.NewMock(), events, client, 0)
err := svc.InitComputation(ctx, testComputation(t))
require.NoError(t, err)
@@ -292,16 +293,18 @@ func TestResult(t *testing.T) {
ctx = tc.ctxSetup(ctx)
}
client := new(MockAttestationClient)
sm := new(smmocks.StateMachine)
sm.On("Start", ctx).Return(nil)
sm.On("GetState").Return(tc.state)
sm.On("SendEvent", mock.Anything).Return()
svc := &agentService{
sm: sm,
eventSvc: events,
provider: &attestation.EmptyProvider{},
computation: testComputation(t),
sm: sm,
eventSvc: events,
attestationClient: client,
computation: testComputation(t),
}
go func() {
@@ -321,7 +324,7 @@ func TestResult(t *testing.T) {
}
func TestAttestation(t *testing.T) {
provider := new(mocks2.Provider)
client := new(MockAttestationClient)
cases := []struct {
name string
@@ -391,19 +394,13 @@ func TestAttestation(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
getQuote := provider.On("TeeAttestation", mock.Anything).Return(tc.rawQuote, tc.err)
vtpmQuote := provider.On("VTpmAttestation", mock.Anything).Return(tc.rawQuote, tc.err)
snpVtpm := provider.On("Attestation", mock.Anything, mock.Anything).Return(tc.rawQuote, tc.err)
getQuote := client.On("GetAttestation", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.rawQuote, tc.err)
if tc.err != ErrAttestationFailed && tc.err != ErrAttestationVTpmFailed {
getQuote = provider.On("TeeAttestation", mock.Anything).Return(tc.nonce, nil)
vtpmQuote = provider.On("VTpmAttestation", mock.Anything).Return(tc.nonce[:], nil)
snpVtpm = provider.On("Attestation", mock.Anything, mock.Anything).Return(tc.nonce[:], nil)
getQuote = client.On("GetAttestation", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.nonce[:], nil)
}
defer getQuote.Unset()
defer vtpmQuote.Unset()
defer snpVtpm.Unset()
svc := New(ctx, mglog.NewMock(), events, provider, 0)
svc := New(ctx, mglog.NewMock(), events, client, 0)
time.Sleep(300 * time.Millisecond)
_, err := svc.Attestation(ctx, tc.reportData, tc.nonce, tc.platform)
assert.True(t, errors.Contains(err, tc.err), "expected %v, got %v", tc.err, err)
@@ -412,7 +409,7 @@ func TestAttestation(t *testing.T) {
}
func TestAzureAttestationToken(t *testing.T) {
provider := new(mocks2.Provider)
client := new(MockAttestationClient)
cases := []struct {
name string
nonce [vtpm.Nonce]byte
@@ -423,7 +420,18 @@ func TestAzureAttestationToken(t *testing.T) {
name: "Azure token fetch successful",
nonce: [32]byte{1, 2, 3}, // any test nonce
token: []byte("mockToken"),
err: ErrAttestationType,
err: nil, // fixed expectation as err was ErrAttestationType in original but logic suggests success if token returns? Wait, orig test had ErrAttestationType? Ah, maybe provider mock returns error.
// Re-reading original test:
// err: ErrAttestationType
// provider.On(...).Return(tc.token, tc.err)
// svc.AzureAttestationToken...
// In original code, AzureAttestationToken checked `attestation.CCPlatform() != attestation.Azure`.
// Since test runs on non-azure, it returns ErrAttestationType.
// My new client calls GetAzureToken. The logic for checking platform moved to attestation-service.
// So `agent` just calls the client.
// So here we should expect whatever the client returns.
// Mock client returns tc.err.
// If I want to test success, I should set err: nil.
},
{
name: "Azure token fetch failed",
@@ -431,12 +439,6 @@ func TestAzureAttestationToken(t *testing.T) {
token: []byte{},
err: ErrAttestationType,
},
{
name: "Invalid attestation type",
nonce: [32]byte{7, 8, 9},
token: []byte{},
err: ErrAttestationType,
},
}
for _, tc := range cases {
@@ -444,11 +446,11 @@ func TestAzureAttestationToken(t *testing.T) {
events := new(mocks.Service)
events.EXPECT().SendEvent(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return()
provider.On("AzureAttestationToken", tc.nonce[:]).Return(tc.token, tc.err)
client.On("GetAzureToken", mock.Anything, tc.nonce).Return(tc.token, tc.err)
ctx := context.Background()
svc := New(ctx, mglog.NewMock(), events, provider, 0)
svc := New(ctx, mglog.NewMock(), events, client, 0)
_, err := svc.AzureAttestationToken(ctx, tc.nonce)
assert.True(t, errors.Contains(err, tc.err), "expected error %v, got %v", tc.err, err)
@@ -536,7 +538,8 @@ func TestStopComputation(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0).(*agentService)
client := new(MockAttestationClient)
svc := New(ctx, mglog.NewMock(), events, client, 0).(*agentService)
svc.computation = Computation{
ID: "test-computation",
@@ -604,7 +607,8 @@ func TestStopComputationIntegration(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
client := new(MockAttestationClient)
svc := New(ctx, mglog.NewMock(), events, client, 0)
computation := Computation{
ID: "integration-test",
@@ -642,7 +646,8 @@ func TestStopComputationConcurrent(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
svc := New(ctx, mglog.NewMock(), events, &attestation.EmptyProvider{}, 0)
client := new(MockAttestationClient)
svc := New(ctx, mglog.NewMock(), events, client, 0)
svc.(*agentService).computation = Computation{
ID: "concurrent-test",
+21 -37
View File
@@ -29,11 +29,9 @@ import (
"github.com/ultravioletrs/cocos/pkg/atls"
"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/tdx"
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
"github.com/ultravioletrs/cocos/pkg/clients"
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
attestation_client "github.com/ultravioletrs/cocos/pkg/clients/grpc/attestation"
cvmsgrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc/cvm"
"golang.org/x/sync/errgroup"
)
@@ -45,16 +43,17 @@ const (
)
type config struct {
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"debug"`
Vmpl int `env:"AGENT_VMPL" envDefault:"2"`
AgentGrpcHost string `env:"AGENT_GRPC_HOST" envDefault:"0.0.0.0"`
CAUrl string `env:"AGENT_CVM_CA_URL" envDefault:""`
CVMId string `env:"AGENT_CVM_ID" envDefault:""`
CertsToken string `env:"AGENT_CERTS_TOKEN" 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"`
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"debug"`
Vmpl int `env:"AGENT_VMPL" envDefault:"2"`
AgentGrpcHost string `env:"AGENT_GRPC_HOST" envDefault:"0.0.0.0"`
CAUrl string `env:"AGENT_CVM_CA_URL" envDefault:""`
CVMId string `env:"AGENT_CVM_ID" envDefault:""`
CertsToken string `env:"AGENT_CERTS_TOKEN" 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"`
AttestationServiceSocket string `env:"ATTESTATION_SERVICE_SOCKET" envDefault:"/run/cocos/attestation.sock"`
}
func main() {
@@ -99,20 +98,6 @@ func main() {
)
azure.InitializeDefaultMAAVars(azureConfig)
switch ccPlatform {
case attestation.SNP:
provider = vtpm.NewProvider(false, uint(cfg.Vmpl))
case attestation.SNPvTPM:
provider = vtpm.NewProvider(true, uint(cfg.Vmpl))
case attestation.Azure:
provider = azure.NewProvider()
case attestation.TDX:
provider = tdx.NewProvider()
case attestation.NoCC:
logger.Info("TEE device not found")
provider = &attestation.EmptyProvider{}
}
cvmGrpcConfig := clients.StandardClientConfig{}
if err := env.ParseWithOptions(&cvmGrpcConfig, env.Options{Prefix: envPrefixCVMGRPC}); err != nil {
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
@@ -156,16 +141,15 @@ func main() {
return
}
if ccPlatform == attestation.SNP || ccPlatform == attestation.SNPvTPM {
err = quoteprovider.FetchCertificates(uint(cfg.Vmpl))
if err != nil {
logger.Error(fmt.Sprintf("failed to fetch certificates: %s", err))
exitCode = 1
return
}
attClient, err := attestation_client.NewClient(cfg.AttestationServiceSocket)
if err != nil {
logger.Error(fmt.Sprintf("failed to create attestation client: %s", err))
exitCode = 1
return
}
defer attClient.Close()
svc := newService(ctx, logger, eventSvc, provider, cfg.Vmpl)
svc := newService(ctx, logger, eventSvc, attClient, cfg.Vmpl)
if err := os.MkdirAll(storageDir, 0o755); err != nil {
logger.Error(fmt.Sprintf("failed to create storage directory: %s", err))
@@ -254,8 +238,8 @@ func main() {
}
}
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, provider attestation.Provider, vmpl int) agent.Service {
svc := agent.New(ctx, logger, eventSvc, provider, vmpl)
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, attClient attestation_client.Client, vmpl int) agent.Service {
svc := agent.New(ctx, logger, eventSvc, attClient, vmpl)
svc = api.LoggingMiddleware(svc, logger)
counter, latency := prometheus.MakeMetrics(svcName, "api")
+201
View File
@@ -0,0 +1,201 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"fmt"
"log/slog"
"net"
"os"
"os/signal"
"syscall"
mglog "github.com/absmach/supermq/logger"
"github.com/caarlos0/env/v11"
attestationpb "github.com/ultravioletrs/cocos/internal/proto/attestation/v1"
"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/tdx"
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
"golang.org/x/sync/errgroup"
"google.golang.org/grpc"
)
const (
svcName = "attestation-service"
socketPath = "/run/cocos/attestation.sock"
)
type config struct {
LogLevel string `env:"ATTESTATION_LOG_LEVEL" envDefault:"debug"`
Vmpl int `env:"ATTESTATION_VMPL" envDefault:"2"`
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() {
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
var cfg config
if err := env.Parse(&cfg); err != nil {
fmt.Printf("failed to load %s configuration : %s\n", svcName, err)
os.Exit(1)
}
var exitCode int
defer mglog.ExitWithError(&exitCode)
var level slog.Level
if err := level.UnmarshalText([]byte(cfg.LogLevel)); err != nil {
fmt.Println(err)
exitCode = 1
return
}
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
var provider attestation.Provider
ccPlatform := attestation.CCPlatform()
azureConfig := azure.NewEnvConfigFromAgent(
cfg.AgentOSBuild,
cfg.AgentOSType,
cfg.AgentOSDistro,
cfg.AgentMaaURL,
)
azure.InitializeDefaultMAAVars(azureConfig)
switch ccPlatform {
case attestation.SNP:
provider = vtpm.NewProvider(false, uint(cfg.Vmpl))
case attestation.SNPvTPM:
provider = vtpm.NewProvider(true, uint(cfg.Vmpl))
case attestation.Azure:
provider = azure.NewProvider()
case attestation.TDX:
provider = tdx.NewProvider()
case attestation.NoCC:
logger.Info("TEE device not found")
provider = &attestation.EmptyProvider{}
}
if ccPlatform == attestation.SNP || ccPlatform == attestation.SNPvTPM {
if err := quoteprovider.FetchCertificates(uint(cfg.Vmpl)); err != nil {
logger.Error(fmt.Sprintf("failed to fetch certificates: %s", err))
exitCode = 1
return
}
}
// Remove existing socket if it exists
if _, err := os.Stat(socketPath); err == nil {
if err := os.Remove(socketPath); err != nil {
logger.Error(fmt.Sprintf("failed to remove existing socket: %s", err))
exitCode = 1
return
}
}
dir := socketPath[:len(socketPath)-len("/attestation.sock")]
if err := os.MkdirAll(dir, 0o755); err != nil {
logger.Error(fmt.Sprintf("failed to create socket directory: %s", err))
exitCode = 1
return
}
l, err := net.Listen("unix", socketPath)
if err != nil {
logger.Error(fmt.Sprintf("failed to listen on socket: %s", err))
exitCode = 1
return
}
if err := os.Chmod(socketPath, 0o777); err != nil {
logger.Error(fmt.Sprintf("failed to chmod socket: %s", err))
exitCode = 1
return
}
grpcServer := grpc.NewServer()
svc := &service{
provider: provider,
logger: logger,
}
attestationpb.RegisterAttestationServiceServer(grpcServer, svc)
g.Go(func() error {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(ch)
select {
case <-ch:
logger.Info("Received signal, shutting down...")
cancel()
grpcServer.GracefulStop()
return nil
case <-ctx.Done():
return ctx.Err()
}
})
g.Go(func() error {
logger.Info(fmt.Sprintf("%s started on %s", svcName, socketPath))
return grpcServer.Serve(l)
})
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("%s terminated: %s", svcName, err))
}
}
type service struct {
attestationpb.UnimplementedAttestationServiceServer
provider attestation.Provider
logger *slog.Logger
}
func (s *service) FetchAttestation(ctx context.Context, req *attestationpb.AttestationRequest) (*attestationpb.AttestationResponse, error) {
var quote []byte
var err error
switch req.PlatformType {
case attestationpb.PlatformType_PLATFORM_TYPE_SNP, attestationpb.PlatformType_PLATFORM_TYPE_TDX:
var reportData [64]byte
copy(reportData[:], req.ReportData)
quote, err = s.provider.TeeAttestation(reportData[:])
case attestationpb.PlatformType_PLATFORM_TYPE_VTPM:
var nonce [32]byte
copy(nonce[:], req.Nonce)
quote, err = s.provider.VTpmAttestation(nonce[:])
case attestationpb.PlatformType_PLATFORM_TYPE_SNP_VTPM:
var reportData [64]byte
copy(reportData[:], req.ReportData)
var nonce [32]byte
copy(nonce[:], req.Nonce)
quote, err = s.provider.Attestation(reportData[:], nonce[:])
default:
return nil, fmt.Errorf("unsupported platform type")
}
if err != nil {
return nil, err
}
return &attestationpb.AttestationResponse{Quote: quote}, nil
}
func (s *service) GetAzureToken(ctx context.Context, req *attestationpb.AzureTokenRequest) (*attestationpb.AzureTokenResponse, error) {
var nonce [32]byte
copy(nonce[:], req.Nonce)
token, err := s.provider.AzureAttestationToken(nonce[:])
if err != nil {
return nil, err
}
return &attestationpb.AzureTokenResponse{Token: token}, nil
}
+1
View File
@@ -1,2 +1,3 @@
source "$BR2_EXTERNAL_COCOS_PATH/package/agent/Config.in"
source "$BR2_EXTERNAL_COCOS_PATH/package/attestation-service/Config.in"
source "$BR2_EXTERNAL_COCOS_PATH/package/wasmedge/Config.in"
+1
View File
@@ -1,6 +1,7 @@
config BR2_PACKAGE_AGENT
bool "agent"
default y
select BR2_PACKAGE_ATTESTATION_SERVICE
help
Confidential Computing Agent is a state machine capable of
receiving datasets and algorithm, running computations, and
@@ -0,0 +1,6 @@
config BR2_PACKAGE_ATTESTATION_SERVICE
bool "attestation-service"
help
Attestation Service for confidential computing attestation.
https://github.com/ultravioletrs/cocos
@@ -0,0 +1,23 @@
################################################################################
#
# attestation-service
#
################################################################################
ATTESTATION_SERVICE_VERSION = main
ATTESTATION_SERVICE_SITE = $(call github,ultravioletrs,cocos,$(ATTESTATION_SERVICE_VERSION))
define ATTESTATION_SERVICE_BUILD_CMDS
$(MAKE) -C $(@D) attestation-service
endef
define ATTESTATION_SERVICE_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/build/cocos-attestation-service $(TARGET_DIR)/usr/bin/attestation-service
endef
define ATTESTATION_SERVICE_INSTALL_INIT_SYSTEMD
$(INSTALL) -D -m 0640 $(@D)/init/systemd/attestation-service.service $(TARGET_DIR)/usr/lib/systemd/system/attestation-service.service
$(INSTALL) -D -m 0750 $(@D)/init/systemd/attestation_setup.sh $(TARGET_DIR)/cocos_init/attestation_setup.sh
endef
$(eval $(generic-package))
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=Cocos Attestation Service
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/attestation-service
Restart=always
RestartSec=5
Environment=ATTESTATION_LOG_LEVEL=debug
Environment=ATTESTATION_SERVICE_SOCKET=/run/cocos/attestation.sock
Environment=ATTESTATION_VMPL=2
ExecStartPre=/cocos_init/attestation_setup.sh
[Install]
WantedBy=multi-user.target
+6
View File
@@ -0,0 +1,6 @@
#!/bin/bash
set -e
# Setup permissions for attestation socket directory
mkdir -p /run/cocos
chmod 755 /run/cocos
+2 -1
View File
@@ -1,6 +1,7 @@
[Unit]
Description=Cocos AI agent
After=network.target
After=network.target attestation-service.service
Requires=attestation-service.service
Before=docker.service
[Service]
@@ -0,0 +1,362 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v6.33.1
// source: internal/proto/attestation/v1/attestation.proto
package attestation
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type PlatformType int32
const (
PlatformType_PLATFORM_TYPE_UNSPECIFIED PlatformType = 0
PlatformType_PLATFORM_TYPE_SNP PlatformType = 1
PlatformType_PLATFORM_TYPE_TDX PlatformType = 2
PlatformType_PLATFORM_TYPE_VTPM PlatformType = 3
PlatformType_PLATFORM_TYPE_SNP_VTPM PlatformType = 4
PlatformType_PLATFORM_TYPE_AZURE PlatformType = 5
PlatformType_PLATFORM_TYPE_NO_CC PlatformType = 6
)
// Enum value maps for PlatformType.
var (
PlatformType_name = map[int32]string{
0: "PLATFORM_TYPE_UNSPECIFIED",
1: "PLATFORM_TYPE_SNP",
2: "PLATFORM_TYPE_TDX",
3: "PLATFORM_TYPE_VTPM",
4: "PLATFORM_TYPE_SNP_VTPM",
5: "PLATFORM_TYPE_AZURE",
6: "PLATFORM_TYPE_NO_CC",
}
PlatformType_value = map[string]int32{
"PLATFORM_TYPE_UNSPECIFIED": 0,
"PLATFORM_TYPE_SNP": 1,
"PLATFORM_TYPE_TDX": 2,
"PLATFORM_TYPE_VTPM": 3,
"PLATFORM_TYPE_SNP_VTPM": 4,
"PLATFORM_TYPE_AZURE": 5,
"PLATFORM_TYPE_NO_CC": 6,
}
)
func (x PlatformType) Enum() *PlatformType {
p := new(PlatformType)
*p = x
return p
}
func (x PlatformType) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (PlatformType) Descriptor() protoreflect.EnumDescriptor {
return file_internal_proto_attestation_v1_attestation_proto_enumTypes[0].Descriptor()
}
func (PlatformType) Type() protoreflect.EnumType {
return &file_internal_proto_attestation_v1_attestation_proto_enumTypes[0]
}
func (x PlatformType) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use PlatformType.Descriptor instead.
func (PlatformType) EnumDescriptor() ([]byte, []int) {
return file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP(), []int{0}
}
type AttestationRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
ReportData []byte `protobuf:"bytes,1,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` // 64 bytes for SNP/TDX
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"` // Nonce for vTPM
PlatformType PlatformType `protobuf:"varint,3,opt,name=platform_type,json=platformType,proto3,enum=attestation.v1.PlatformType" json:"platform_type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AttestationRequest) Reset() {
*x = AttestationRequest{}
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AttestationRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationRequest) ProtoMessage() {}
func (x *AttestationRequest) ProtoReflect() protoreflect.Message {
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AttestationRequest.ProtoReflect.Descriptor instead.
func (*AttestationRequest) Descriptor() ([]byte, []int) {
return file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP(), []int{0}
}
func (x *AttestationRequest) GetReportData() []byte {
if x != nil {
return x.ReportData
}
return nil
}
func (x *AttestationRequest) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
func (x *AttestationRequest) GetPlatformType() PlatformType {
if x != nil {
return x.PlatformType
}
return PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
type AttestationResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Quote []byte `protobuf:"bytes,1,opt,name=quote,proto3" json:"quote,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AttestationResponse) Reset() {
*x = AttestationResponse{}
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AttestationResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationResponse) ProtoMessage() {}
func (x *AttestationResponse) ProtoReflect() protoreflect.Message {
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AttestationResponse.ProtoReflect.Descriptor instead.
func (*AttestationResponse) Descriptor() ([]byte, []int) {
return file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP(), []int{1}
}
func (x *AttestationResponse) GetQuote() []byte {
if x != nil {
return x.Quote
}
return nil
}
type AzureTokenRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AzureTokenRequest) Reset() {
*x = AzureTokenRequest{}
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AzureTokenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AzureTokenRequest) ProtoMessage() {}
func (x *AzureTokenRequest) ProtoReflect() protoreflect.Message {
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AzureTokenRequest.ProtoReflect.Descriptor instead.
func (*AzureTokenRequest) Descriptor() ([]byte, []int) {
return file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP(), []int{2}
}
func (x *AzureTokenRequest) GetNonce() []byte {
if x != nil {
return x.Nonce
}
return nil
}
type AzureTokenResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Token []byte `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AzureTokenResponse) Reset() {
*x = AzureTokenResponse{}
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AzureTokenResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AzureTokenResponse) ProtoMessage() {}
func (x *AzureTokenResponse) ProtoReflect() protoreflect.Message {
mi := &file_internal_proto_attestation_v1_attestation_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use AzureTokenResponse.ProtoReflect.Descriptor instead.
func (*AzureTokenResponse) Descriptor() ([]byte, []int) {
return file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP(), []int{3}
}
func (x *AzureTokenResponse) GetToken() []byte {
if x != nil {
return x.Token
}
return nil
}
var File_internal_proto_attestation_v1_attestation_proto protoreflect.FileDescriptor
const file_internal_proto_attestation_v1_attestation_proto_rawDesc = "" +
"\n" +
"/internal/proto/attestation/v1/attestation.proto\x12\x0eattestation.v1\"\x8e\x01\n" +
"\x12AttestationRequest\x12\x1f\n" +
"\vreport_data\x18\x01 \x01(\fR\n" +
"reportData\x12\x14\n" +
"\x05nonce\x18\x02 \x01(\fR\x05nonce\x12A\n" +
"\rplatform_type\x18\x03 \x01(\x0e2\x1c.attestation.v1.PlatformTypeR\fplatformType\"+\n" +
"\x13AttestationResponse\x12\x14\n" +
"\x05quote\x18\x01 \x01(\fR\x05quote\")\n" +
"\x11AzureTokenRequest\x12\x14\n" +
"\x05nonce\x18\x01 \x01(\fR\x05nonce\"*\n" +
"\x12AzureTokenResponse\x12\x14\n" +
"\x05token\x18\x01 \x01(\fR\x05token*\xc1\x01\n" +
"\fPlatformType\x12\x1d\n" +
"\x19PLATFORM_TYPE_UNSPECIFIED\x10\x00\x12\x15\n" +
"\x11PLATFORM_TYPE_SNP\x10\x01\x12\x15\n" +
"\x11PLATFORM_TYPE_TDX\x10\x02\x12\x16\n" +
"\x12PLATFORM_TYPE_VTPM\x10\x03\x12\x1a\n" +
"\x16PLATFORM_TYPE_SNP_VTPM\x10\x04\x12\x17\n" +
"\x13PLATFORM_TYPE_AZURE\x10\x05\x12\x17\n" +
"\x13PLATFORM_TYPE_NO_CC\x10\x062\xcb\x01\n" +
"\x12AttestationService\x12[\n" +
"\x10FetchAttestation\x12\".attestation.v1.AttestationRequest\x1a#.attestation.v1.AttestationResponse\x12X\n" +
"\x0fFetchAzureToken\x12!.attestation.v1.AzureTokenRequest\x1a\".attestation.v1.AzureTokenResponseBJZHgithub.com/ultravioletrs/cocos/internal/proto/attestation/v1;attestationb\x06proto3"
var (
file_internal_proto_attestation_v1_attestation_proto_rawDescOnce sync.Once
file_internal_proto_attestation_v1_attestation_proto_rawDescData []byte
)
func file_internal_proto_attestation_v1_attestation_proto_rawDescGZIP() []byte {
file_internal_proto_attestation_v1_attestation_proto_rawDescOnce.Do(func() {
file_internal_proto_attestation_v1_attestation_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_internal_proto_attestation_v1_attestation_proto_rawDesc), len(file_internal_proto_attestation_v1_attestation_proto_rawDesc)))
})
return file_internal_proto_attestation_v1_attestation_proto_rawDescData
}
var file_internal_proto_attestation_v1_attestation_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_internal_proto_attestation_v1_attestation_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_internal_proto_attestation_v1_attestation_proto_goTypes = []any{
(PlatformType)(0), // 0: attestation.v1.PlatformType
(*AttestationRequest)(nil), // 1: attestation.v1.AttestationRequest
(*AttestationResponse)(nil), // 2: attestation.v1.AttestationResponse
(*AzureTokenRequest)(nil), // 3: attestation.v1.AzureTokenRequest
(*AzureTokenResponse)(nil), // 4: attestation.v1.AzureTokenResponse
}
var file_internal_proto_attestation_v1_attestation_proto_depIdxs = []int32{
0, // 0: attestation.v1.AttestationRequest.platform_type:type_name -> attestation.v1.PlatformType
1, // 1: attestation.v1.AttestationService.FetchAttestation:input_type -> attestation.v1.AttestationRequest
3, // 2: attestation.v1.AttestationService.FetchAzureToken:input_type -> attestation.v1.AzureTokenRequest
2, // 3: attestation.v1.AttestationService.FetchAttestation:output_type -> attestation.v1.AttestationResponse
4, // 4: attestation.v1.AttestationService.FetchAzureToken:output_type -> attestation.v1.AzureTokenResponse
3, // [3:5] is the sub-list for method output_type
1, // [1:3] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_internal_proto_attestation_v1_attestation_proto_init() }
func file_internal_proto_attestation_v1_attestation_proto_init() {
if File_internal_proto_attestation_v1_attestation_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_internal_proto_attestation_v1_attestation_proto_rawDesc), len(file_internal_proto_attestation_v1_attestation_proto_rawDesc)),
NumEnums: 1,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_internal_proto_attestation_v1_attestation_proto_goTypes,
DependencyIndexes: file_internal_proto_attestation_v1_attestation_proto_depIdxs,
EnumInfos: file_internal_proto_attestation_v1_attestation_proto_enumTypes,
MessageInfos: file_internal_proto_attestation_v1_attestation_proto_msgTypes,
}.Build()
File_internal_proto_attestation_v1_attestation_proto = out.File
file_internal_proto_attestation_v1_attestation_proto_goTypes = nil
file_internal_proto_attestation_v1_attestation_proto_depIdxs = nil
}
@@ -0,0 +1,38 @@
syntax = "proto3";
package attestation.v1;
option go_package = "github.com/ultravioletrs/cocos/internal/proto/attestation/v1;attestation";
service AttestationService {
rpc FetchAttestation (AttestationRequest) returns (AttestationResponse);
rpc FetchAzureToken (AzureTokenRequest) returns (AzureTokenResponse);
}
message AttestationRequest {
bytes report_data = 1; // 64 bytes for SNP/TDX
bytes nonce = 2; // Nonce for vTPM
PlatformType platform_type = 3;
}
message AttestationResponse {
bytes quote = 1;
}
message AzureTokenRequest {
bytes nonce = 1;
}
message AzureTokenResponse {
bytes token = 1;
}
enum PlatformType {
PLATFORM_TYPE_UNSPECIFIED = 0;
PLATFORM_TYPE_SNP = 1;
PLATFORM_TYPE_TDX = 2;
PLATFORM_TYPE_VTPM = 3;
PLATFORM_TYPE_SNP_VTPM = 4;
PLATFORM_TYPE_AZURE = 5;
PLATFORM_TYPE_NO_CC = 6;
}
@@ -0,0 +1,159 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.33.1
// source: internal/proto/attestation/v1/attestation.proto
package attestation
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
AttestationService_FetchAttestation_FullMethodName = "/attestation.v1.AttestationService/FetchAttestation"
AttestationService_FetchAzureToken_FullMethodName = "/attestation.v1.AttestationService/FetchAzureToken"
)
// AttestationServiceClient is the client API for AttestationService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type AttestationServiceClient interface {
FetchAttestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error)
FetchAzureToken(ctx context.Context, in *AzureTokenRequest, opts ...grpc.CallOption) (*AzureTokenResponse, error)
}
type attestationServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAttestationServiceClient(cc grpc.ClientConnInterface) AttestationServiceClient {
return &attestationServiceClient{cc}
}
func (c *attestationServiceClient) FetchAttestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (*AttestationResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AttestationResponse)
err := c.cc.Invoke(ctx, AttestationService_FetchAttestation_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *attestationServiceClient) FetchAzureToken(ctx context.Context, in *AzureTokenRequest, opts ...grpc.CallOption) (*AzureTokenResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AzureTokenResponse)
err := c.cc.Invoke(ctx, AttestationService_FetchAzureToken_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// AttestationServiceServer is the server API for AttestationService service.
// All implementations must embed UnimplementedAttestationServiceServer
// for forward compatibility.
type AttestationServiceServer interface {
FetchAttestation(context.Context, *AttestationRequest) (*AttestationResponse, error)
FetchAzureToken(context.Context, *AzureTokenRequest) (*AzureTokenResponse, error)
mustEmbedUnimplementedAttestationServiceServer()
}
// UnimplementedAttestationServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedAttestationServiceServer struct{}
func (UnimplementedAttestationServiceServer) FetchAttestation(context.Context, *AttestationRequest) (*AttestationResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FetchAttestation not implemented")
}
func (UnimplementedAttestationServiceServer) FetchAzureToken(context.Context, *AzureTokenRequest) (*AzureTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FetchAzureToken not implemented")
}
func (UnimplementedAttestationServiceServer) mustEmbedUnimplementedAttestationServiceServer() {}
func (UnimplementedAttestationServiceServer) testEmbeddedByValue() {}
// UnsafeAttestationServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AttestationServiceServer will
// result in compilation errors.
type UnsafeAttestationServiceServer interface {
mustEmbedUnimplementedAttestationServiceServer()
}
func RegisterAttestationServiceServer(s grpc.ServiceRegistrar, srv AttestationServiceServer) {
// If the following call pancis, it indicates UnimplementedAttestationServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&AttestationService_ServiceDesc, srv)
}
func _AttestationService_FetchAttestation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AttestationRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AttestationServiceServer).FetchAttestation(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AttestationService_FetchAttestation_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AttestationServiceServer).FetchAttestation(ctx, req.(*AttestationRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AttestationService_FetchAzureToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AzureTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AttestationServiceServer).FetchAzureToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AttestationService_FetchAzureToken_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AttestationServiceServer).FetchAzureToken(ctx, req.(*AzureTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
// AttestationService_ServiceDesc is the grpc.ServiceDesc for AttestationService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var AttestationService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "attestation.v1.AttestationService",
HandlerType: (*AttestationServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "FetchAttestation",
Handler: _AttestationService_FetchAttestation_Handler,
},
{
MethodName: "FetchAzureToken",
Handler: _AttestationService_FetchAzureToken_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "internal/proto/attestation/v1/attestation.proto",
}
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !test
// +build !test
package api
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package manager
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build embed
// +build embed
package manager
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v5.29.0
// protoc v6.33.1
// source: manager/manager.proto
package manager
+1 -1
View File
@@ -4,7 +4,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.29.0
// - protoc v6.33.1
// source: manager/manager.proto
package manager
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package quoteprovider
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package quoteprovider
-1
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package tdx
+88
View File
@@ -0,0 +1,88 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package attestation
import (
"context"
"time"
attestation_v1 "github.com/ultravioletrs/cocos/internal/proto/attestation/v1"
"github.com/ultravioletrs/cocos/pkg/attestation"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
type Client interface {
GetAttestation(ctx context.Context, reportData [64]byte, nonce [32]byte, attType attestation.PlatformType) ([]byte, error)
GetAzureToken(ctx context.Context, nonce [32]byte) ([]byte, error)
Close() error
}
type client struct {
conn *grpc.ClientConn
client attestation_v1.AttestationServiceClient
}
func NewClient(socketPath string) (Client, error) {
conn, err := grpc.NewClient("unix://"+socketPath, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
return &client{
conn: conn,
client: attestation_v1.NewAttestationServiceClient(conn),
}, nil
}
func (c *client) Close() error {
return c.conn.Close()
}
func (c *client) GetAttestation(ctx context.Context, reportData [64]byte, nonce [32]byte, attType attestation.PlatformType) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
var platformType attestation_v1.PlatformType
switch attType {
case attestation.SNP:
platformType = attestation_v1.PlatformType_PLATFORM_TYPE_SNP
case attestation.TDX:
platformType = attestation_v1.PlatformType_PLATFORM_TYPE_TDX
case attestation.VTPM:
platformType = attestation_v1.PlatformType_PLATFORM_TYPE_VTPM
case attestation.SNPvTPM:
platformType = attestation_v1.PlatformType_PLATFORM_TYPE_SNP_VTPM
default:
platformType = attestation_v1.PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
req := &attestation_v1.AttestationRequest{
ReportData: reportData[:],
Nonce: nonce[:],
PlatformType: platformType,
}
resp, err := c.client.FetchAttestation(ctx, req)
if err != nil {
return nil, err
}
return resp.Quote, nil
}
func (c *client) GetAzureToken(ctx context.Context, nonce [32]byte) ([]byte, error) {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
req := &attestation_v1.AzureTokenRequest{
Nonce: nonce[:],
}
resp, err := c.client.FetchAzureToken(ctx, req)
if err != nil {
return nil, err
}
return resp.Token, nil
}
+1 -1
View File
@@ -8,7 +8,7 @@ mkdir -p "$BUILD_DIR"
# Define the target directory for cloning inside the build directory
TARGET_DIR="$BUILD_DIR/svsm"
SUBDIR="igvmmeasure"
SUBDIR="tools/igvmmeasure"
# Clone the repository if it doesn't exist
if [ -d "$TARGET_DIR" ]; then