COCOS-394 Cloud Provider Attestation Service Integration (#421)

* Add token measurement command

Add Azure cloud attestation fetching

Add ability to fetch azure attestation token

Remove gcp changes

Remove gcp changes

Add Azure attestation support

Modify pipeline proto checks

Update protoc version

Fix failing CI

fetch token as a file

Convert jwt to json

Small bug fix -- correct file name for attestation token

Fix failing CI

Modify protoc version

Update protoc version

Update protoc version

Update protoc version

Add changes to allow passing vtpm nonce

Add PR review changes to refactor the code

Refactor name change to AttestationResult

Refactor name change to AttestationResult

Return report as json

Format files properly

Fix attestaton changes

Modify changes based on PR review

Add more test coverage

Correct bug in Server test

Rename "FetchAttestationResult" to "AttestationResult"

Send token as part of stream

Fix CI

NOISSUE -  Add DisconnectReq message and TTL support for VM creation (#428)

* feat: Add DisconnectReq message and TTL support for VM creation

- Introduced DisconnectReq message in cvms.proto to handle disconnection requests.
- Enhanced CreateReq in manager.proto to include a TTL field for virtual machines.
- Updated CLI to accept TTL as a command-line flag during VM creation.
- Modified manager service to remove VMs after the specified TTL duration.
- Adjusted gRPC client connection handling in agent main.go to support new client structure.
- Added mock implementation for gRPC client to facilitate testing.

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

* fix: Mark server URL flag as required with error handling

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

---------

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

COCOS-407 - Add support for Linux IMA (#429)

* Added a feature which enables users to fetch IMA measurements and verify them

* Added a feature which enables users to fetch IMA measurements and verify them

* fixed lint error

* fixed according to comments

* fixed according to comments

* fixed according to comments

* fixed according to comments

* final bug fix

Add token measurement command

Add Azure cloud attestation fetching

Add ability to fetch azure attestation token

Remove gcp changes

Remove gcp changes

Add Azure attestation support

Modify pipeline proto checks

Update protoc version

Fix failing CI

fetch token as a file

Convert jwt to json

Small bug fix -- correct file name for attestation token

Fix failing CI

Modify protoc version

Update protoc version

Update protoc version

Update protoc version

Add changes to allow passing vtpm nonce

Add PR review changes to refactor the code

Refactor name change to AttestationResult

Refactor name change to AttestationResult

Return report as json

Format files properly

Fix attestaton changes

Modify changes based on PR review

Add more test coverage

Correct bug in Server test

Rename "FetchAttestationResult" to "AttestationResult"

Send token as part of stream

Fix CI

Rebase changes to main

Refactor after rebase

* Add Azure attestation

* 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>

* Add token measurement command

Add Azure cloud attestation fetching

Add ability to fetch azure attestation token

Remove gcp changes

Remove gcp changes

Add Azure attestation support

Modify pipeline proto checks

Update protoc version

Fix failing CI

fetch token as a file

Convert jwt to json

Small bug fix -- correct file name for attestation token

Fix failing CI

Modify protoc version

Update protoc version

Update protoc version

Update protoc version

Add changes to allow passing vtpm nonce

Add PR review changes to refactor the code

Refactor name change to AttestationResult

Refactor name change to AttestationResult

Return report as json

Format files properly

Fix attestaton changes

Modify changes based on PR review

Add more test coverage

Correct bug in Server test

Rename "FetchAttestationResult" to "AttestationResult"

Send token as part of stream

Fix CI

NOISSUE -  Add DisconnectReq message and TTL support for VM creation (#428)

* feat: Add DisconnectReq message and TTL support for VM creation

- Introduced DisconnectReq message in cvms.proto to handle disconnection requests.
- Enhanced CreateReq in manager.proto to include a TTL field for virtual machines.
- Updated CLI to accept TTL as a command-line flag during VM creation.
- Modified manager service to remove VMs after the specified TTL duration.
- Adjusted gRPC client connection handling in agent main.go to support new client structure.
- Added mock implementation for gRPC client to facilitate testing.

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

* fix: Mark server URL flag as required with error handling

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

---------

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

COCOS-407 - Add support for Linux IMA (#429)

* Added a feature which enables users to fetch IMA measurements and verify them

* Added a feature which enables users to fetch IMA measurements and verify them

* fixed lint error

* fixed according to comments

* fixed according to comments

* fixed according to comments

* fixed according to comments

* final bug fix

Add token measurement command

Add Azure cloud attestation fetching

Add ability to fetch azure attestation token

Remove gcp changes

Remove gcp changes

Add Azure attestation support

Modify pipeline proto checks

Update protoc version

Fix failing CI

fetch token as a file

Convert jwt to json

Small bug fix -- correct file name for attestation token

Fix failing CI

Modify protoc version

Update protoc version

Update protoc version

Update protoc version

Add changes to allow passing vtpm nonce

Add PR review changes to refactor the code

Refactor name change to AttestationResult

Refactor name change to AttestationResult

Return report as json

Format files properly

Fix attestaton changes

Modify changes based on PR review

Add more test coverage

Correct bug in Server test

Rename "FetchAttestationResult" to "AttestationResult"

Send token as part of stream

Fix CI

Rebase changes to main

Refactor after rebase

* Rebase with main

* Modify tests to accomodate changes

* Use env vars appropriately

* Use env vars appropriately

* Use caps in err name

---------

Co-authored-by: Danko Miladinovic <72250944+danko-miladinovic@users.noreply.github.com>
Co-authored-by: Ubuntu <azureuser@UVCTestCVM.bu0p0zdolasezg1jifpyqhaxuc.dx.internal.cloudapp.net>
This commit is contained in:
dorcaslitunya
2025-05-21 13:01:49 +03:00
committed by GitHub
parent 3102114ff3
commit 94c169febb
32 changed files with 1424 additions and 288 deletions
+1
View File
@@ -9,6 +9,7 @@ on:
- "pkg/manager/*.pb.go"
- "agent/agent.proto"
- "agent/*.pb.go"
pull_request:
branches:
- main
+163 -49
View File
@@ -472,6 +472,102 @@ func (x *IMAMeasurementsResponse) GetPcr10() []byte {
return nil
}
type AttestationResultRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
TokenNonce []byte `protobuf:"bytes,1,opt,name=tokenNonce,proto3" json:"tokenNonce,omitempty"` // Should be less or equal 32 bytes
Type int32 `protobuf:"varint,3,opt,name=type,proto3" json:"type,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AttestationResultRequest) Reset() {
*x = AttestationResultRequest{}
mi := &file_agent_agent_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AttestationResultRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationResultRequest) ProtoMessage() {}
func (x *AttestationResultRequest) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[10]
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 AttestationResultRequest.ProtoReflect.Descriptor instead.
func (*AttestationResultRequest) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{10}
}
func (x *AttestationResultRequest) GetTokenNonce() []byte {
if x != nil {
return x.TokenNonce
}
return nil
}
func (x *AttestationResultRequest) GetType() int32 {
if x != nil {
return x.Type
}
return 0
}
type AttestationResultResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AttestationResultResponse) Reset() {
*x = AttestationResultResponse{}
mi := &file_agent_agent_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AttestationResultResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AttestationResultResponse) ProtoMessage() {}
func (x *AttestationResultResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_agent_proto_msgTypes[11]
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 AttestationResultResponse.ProtoReflect.Descriptor instead.
func (*AttestationResultResponse) Descriptor() ([]byte, []int) {
return file_agent_agent_proto_rawDescGZIP(), []int{11}
}
func (x *AttestationResultResponse) GetFile() []byte {
if x != nil {
return x.File
}
return nil
}
var File_agent_agent_proto protoreflect.FileDescriptor
var file_agent_agent_proto_rawDesc = string([]byte{
@@ -506,29 +602,43 @@ var file_agent_agent_proto_rawDesc = string([]byte{
0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12,
0x14, 0x0a, 0x05, 0x70, 0x63, 0x72, 0x31, 0x30, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05,
0x70, 0x63, 0x72, 0x31, 0x30, 0x32, 0xd3, 0x02, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x41, 0x6c, 0x67, 0x6f, 0x12, 0x12,
0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x33, 0x0a, 0x04, 0x44,
0x61, 0x74, 0x61, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, 0x74, 0x61,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01,
0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x67, 0x65,
0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x0b, 0x41,
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x67, 0x65,
0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74,
0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x49, 0x4d, 0x41, 0x4d, 0x65, 0x61, 0x73,
0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x70, 0x63, 0x72, 0x31, 0x30, 0x22, 0x4e, 0x0a, 0x18, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4e, 0x6f, 0x6e, 0x63,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2f, 0x0a, 0x19, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x32, 0xad, 0x03, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x41, 0x6c, 0x67, 0x6f, 0x12,
0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x6c, 0x67, 0x6f,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x33, 0x0a, 0x04,
0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x61, 0x74,
0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28,
0x01, 0x12, 0x39, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x2e, 0x61, 0x67,
0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x15, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x48, 0x0a, 0x0b,
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x67,
0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41,
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x49, 0x4d, 0x41, 0x4d, 0x65, 0x61,
0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e,
0x74, 0x2e, 0x49, 0x4d, 0x41, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x2e, 0x49, 0x4d, 0x41, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
0x49, 0x4d, 0x41, 0x4d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e,
0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x58, 0x0a, 0x11,
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x12, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x67, 0x65, 0x6e,
0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
})
var (
@@ -543,35 +653,39 @@ func file_agent_agent_proto_rawDescGZIP() []byte {
return file_agent_agent_proto_rawDescData
}
var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_agent_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_agent_agent_proto_goTypes = []any{
(*AlgoRequest)(nil), // 0: agent.AlgoRequest
(*AlgoResponse)(nil), // 1: agent.AlgoResponse
(*DataRequest)(nil), // 2: agent.DataRequest
(*DataResponse)(nil), // 3: agent.DataResponse
(*ResultRequest)(nil), // 4: agent.ResultRequest
(*ResultResponse)(nil), // 5: agent.ResultResponse
(*AttestationRequest)(nil), // 6: agent.AttestationRequest
(*AttestationResponse)(nil), // 7: agent.AttestationResponse
(*IMAMeasurementsRequest)(nil), // 8: agent.IMAMeasurementsRequest
(*IMAMeasurementsResponse)(nil), // 9: agent.IMAMeasurementsResponse
(*AlgoRequest)(nil), // 0: agent.AlgoRequest
(*AlgoResponse)(nil), // 1: agent.AlgoResponse
(*DataRequest)(nil), // 2: agent.DataRequest
(*DataResponse)(nil), // 3: agent.DataResponse
(*ResultRequest)(nil), // 4: agent.ResultRequest
(*ResultResponse)(nil), // 5: agent.ResultResponse
(*AttestationRequest)(nil), // 6: agent.AttestationRequest
(*AttestationResponse)(nil), // 7: agent.AttestationResponse
(*IMAMeasurementsRequest)(nil), // 8: agent.IMAMeasurementsRequest
(*IMAMeasurementsResponse)(nil), // 9: agent.IMAMeasurementsResponse
(*AttestationResultRequest)(nil), // 10: agent.AttestationResultRequest
(*AttestationResultResponse)(nil), // 11: agent.AttestationResultResponse
}
var file_agent_agent_proto_depIdxs = []int32{
0, // 0: agent.AgentService.Algo:input_type -> agent.AlgoRequest
2, // 1: agent.AgentService.Data:input_type -> agent.DataRequest
4, // 2: agent.AgentService.Result:input_type -> agent.ResultRequest
6, // 3: agent.AgentService.Attestation:input_type -> agent.AttestationRequest
8, // 4: agent.AgentService.IMAMeasurements:input_type -> agent.IMAMeasurementsRequest
1, // 5: agent.AgentService.Algo:output_type -> agent.AlgoResponse
3, // 6: agent.AgentService.Data:output_type -> agent.DataResponse
5, // 7: agent.AgentService.Result:output_type -> agent.ResultResponse
7, // 8: agent.AgentService.Attestation:output_type -> agent.AttestationResponse
9, // 9: agent.AgentService.IMAMeasurements:output_type -> agent.IMAMeasurementsResponse
5, // [5:10] is the sub-list for method output_type
0, // [0:5] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
0, // 0: agent.AgentService.Algo:input_type -> agent.AlgoRequest
2, // 1: agent.AgentService.Data:input_type -> agent.DataRequest
4, // 2: agent.AgentService.Result:input_type -> agent.ResultRequest
6, // 3: agent.AgentService.Attestation:input_type -> agent.AttestationRequest
8, // 4: agent.AgentService.IMAMeasurements:input_type -> agent.IMAMeasurementsRequest
10, // 5: agent.AgentService.AttestationResult:input_type -> agent.AttestationResultRequest
1, // 6: agent.AgentService.Algo:output_type -> agent.AlgoResponse
3, // 7: agent.AgentService.Data:output_type -> agent.DataResponse
5, // 8: agent.AgentService.Result:output_type -> agent.ResultResponse
7, // 9: agent.AgentService.Attestation:output_type -> agent.AttestationResponse
9, // 10: agent.AgentService.IMAMeasurements:output_type -> agent.IMAMeasurementsResponse
11, // 11: agent.AgentService.AttestationResult:output_type -> agent.AttestationResultResponse
6, // [6:12] is the sub-list for method output_type
0, // [0:6] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_agent_agent_proto_init() }
@@ -585,7 +699,7 @@ func file_agent_agent_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_agent_agent_proto_rawDesc), len(file_agent_agent_proto_rawDesc)),
NumEnums: 0,
NumMessages: 10,
NumMessages: 12,
NumExtensions: 0,
NumServices: 1,
},
+9
View File
@@ -13,6 +13,7 @@ service AgentService {
rpc Result(ResultRequest) returns (stream ResultResponse) {}
rpc Attestation(AttestationRequest) returns (stream AttestationResponse) {}
rpc IMAMeasurements(IMAMeasurementsRequest) returns (stream IMAMeasurementsResponse) {}
rpc AttestationResult(AttestationResultRequest) returns (AttestationResultResponse) {}
}
message AlgoRequest {
@@ -53,3 +54,11 @@ message IMAMeasurementsResponse {
bytes file = 1;
bytes pcr10 = 2;
}
message AttestationResultRequest{
bytes tokenNonce = 1; // Should be less or equal 32 bytes
int32 type = 3;
}
message AttestationResultResponse{
bytes file = 1;
}
+45 -6
View File
@@ -22,11 +22,12 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
AgentService_Algo_FullMethodName = "/agent.AgentService/Algo"
AgentService_Data_FullMethodName = "/agent.AgentService/Data"
AgentService_Result_FullMethodName = "/agent.AgentService/Result"
AgentService_Attestation_FullMethodName = "/agent.AgentService/Attestation"
AgentService_IMAMeasurements_FullMethodName = "/agent.AgentService/IMAMeasurements"
AgentService_Algo_FullMethodName = "/agent.AgentService/Algo"
AgentService_Data_FullMethodName = "/agent.AgentService/Data"
AgentService_Result_FullMethodName = "/agent.AgentService/Result"
AgentService_Attestation_FullMethodName = "/agent.AgentService/Attestation"
AgentService_IMAMeasurements_FullMethodName = "/agent.AgentService/IMAMeasurements"
AgentService_AttestationResult_FullMethodName = "/agent.AgentService/AttestationResult"
)
// AgentServiceClient is the client API for AgentService service.
@@ -38,6 +39,7 @@ type AgentServiceClient interface {
Result(ctx context.Context, in *ResultRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ResultResponse], error)
Attestation(ctx context.Context, in *AttestationRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[AttestationResponse], error)
IMAMeasurements(ctx context.Context, in *IMAMeasurementsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IMAMeasurementsResponse], error)
AttestationResult(ctx context.Context, in *AttestationResultRequest, opts ...grpc.CallOption) (*AttestationResultResponse, error)
}
type agentServiceClient struct {
@@ -131,6 +133,16 @@ func (c *agentServiceClient) IMAMeasurements(ctx context.Context, in *IMAMeasure
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type AgentService_IMAMeasurementsClient = grpc.ServerStreamingClient[IMAMeasurementsResponse]
func (c *agentServiceClient) AttestationResult(ctx context.Context, in *AttestationResultRequest, opts ...grpc.CallOption) (*AttestationResultResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AttestationResultResponse)
err := c.cc.Invoke(ctx, AgentService_AttestationResult_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// AgentServiceServer is the server API for AgentService service.
// All implementations must embed UnimplementedAgentServiceServer
// for forward compatibility.
@@ -140,6 +152,7 @@ type AgentServiceServer interface {
Result(*ResultRequest, grpc.ServerStreamingServer[ResultResponse]) error
Attestation(*AttestationRequest, grpc.ServerStreamingServer[AttestationResponse]) error
IMAMeasurements(*IMAMeasurementsRequest, grpc.ServerStreamingServer[IMAMeasurementsResponse]) error
AttestationResult(context.Context, *AttestationResultRequest) (*AttestationResultResponse, error)
mustEmbedUnimplementedAgentServiceServer()
}
@@ -165,6 +178,9 @@ func (UnimplementedAgentServiceServer) Attestation(*AttestationRequest, grpc.Ser
func (UnimplementedAgentServiceServer) IMAMeasurements(*IMAMeasurementsRequest, grpc.ServerStreamingServer[IMAMeasurementsResponse]) error {
return status.Errorf(codes.Unimplemented, "method IMAMeasurements not implemented")
}
func (UnimplementedAgentServiceServer) AttestationResult(context.Context, *AttestationResultRequest) (*AttestationResultResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AttestationResult not implemented")
}
func (UnimplementedAgentServiceServer) mustEmbedUnimplementedAgentServiceServer() {}
func (UnimplementedAgentServiceServer) testEmbeddedByValue() {}
@@ -233,13 +249,36 @@ func _AgentService_IMAMeasurements_Handler(srv interface{}, stream grpc.ServerSt
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type AgentService_IMAMeasurementsServer = grpc.ServerStreamingServer[IMAMeasurementsResponse]
func _AgentService_AttestationResult_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AttestationResultRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServiceServer).AttestationResult(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AgentService_AttestationResult_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServiceServer).AttestationResult(ctx, req.(*AttestationResultRequest))
}
return interceptor(ctx, in, info, handler)
}
// AgentService_ServiceDesc is the grpc.ServiceDesc for AgentService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var AgentService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "agent.AgentService",
HandlerType: (*AgentServiceServer)(nil),
Methods: []grpc.MethodDesc{},
Methods: []grpc.MethodDesc{
{
MethodName: "AttestationResult",
Handler: _AgentService_AttestationResult_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "Algo",
+14
View File
@@ -95,3 +95,17 @@ func imaMeasurementsEndpoint(svc agent.Service) endpoint.Endpoint {
return imaMeasurementsRes{File: file, PCR10: pcr10}, nil
}
}
func attestationResultEndpoint(svc agent.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(FetchAttestationResultReq)
if err := req.validate(); err != nil {
return fetchAttestationResultRes{}, err
}
file, err := svc.AttestationResult(ctx, req.tokenNonce, attestation.PlatformType(req.AttType))
if err != nil {
return fetchAttestationResultRes{}, err
}
return fetchAttestationResultRes{File: file}, nil
}
}
+53
View File
@@ -7,6 +7,7 @@ import (
"errors"
"testing"
"github.com/stretchr/testify/mock"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/agent/mocks"
"github.com/ultravioletrs/cocos/pkg/attestation"
@@ -172,3 +173,55 @@ func TestAttestationEndpoint(t *testing.T) {
})
}
}
func TestAttestationResultEndpoint(t *testing.T) {
svc := new(mocks.Service)
tests := []struct {
name string
req FetchAttestationResultReq
mockErr error
expectedErr bool
}{
{
name: "Success",
req: FetchAttestationResultReq{tokenNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: attestation.AzureToken},
mockErr: nil,
expectedErr: false,
},
{
name: "Service Error",
req: FetchAttestationResultReq{tokenNonce: sha3.Sum256([]byte("vtpm nonce")), AttType: attestation.AzureToken},
mockErr: errors.New("mock failure"),
expectedErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Only call service mock if validation is expected to pass
if err := tt.req.validate(); err == nil {
svc.On("AttestationResult", mock.Anything, tt.req.tokenNonce, attestation.PlatformType(tt.req.AttType)).
Return([]byte("mock file"), tt.mockErr).Once()
}
endpoint := attestationResultEndpoint(svc)
res, err := endpoint(context.Background(), tt.req)
if (err != nil) != tt.expectedErr {
t.Errorf("attestationResultEndpoint() error = %v, expectedErr %v", err, tt.expectedErr)
}
if !tt.expectedErr {
r, ok := res.(fetchAttestationResultRes)
if !ok {
t.Errorf("attestationResultEndpoint() returned unexpected type %T", res)
}
if string(r.File) != "mock file" {
t.Errorf("expected file content 'mock file', got %s", r.File)
}
}
svc.AssertExpectations(t)
})
}
}
+16 -3
View File
@@ -47,12 +47,25 @@ type attestationReq struct {
AttType attestation.PlatformType
}
type FetchAttestationResultReq struct {
tokenNonce [vtpm.Nonce]byte
AttType attestation.PlatformType
}
func (req attestationReq) validate() error {
switch req.AttType {
case attestation.SNP, attestation.VTPM, attestation.SNPvTPM:
return validateAttestationType(req.AttType)
}
func (req FetchAttestationResultReq) validate() error {
return validateAttestationType(req.AttType)
}
func validateAttestationType(attType attestation.PlatformType) error {
switch attType {
case attestation.SNP, attestation.VTPM, attestation.SNPvTPM, attestation.AzureToken:
return nil
default:
return errors.New("invalid attestation type in attestation request")
return errors.New("invalid attestation type")
}
}
+4
View File
@@ -18,3 +18,7 @@ type imaMeasurementsRes struct {
File []byte
PCR10 []byte
}
type fetchAttestationResultRes struct {
File []byte `protobuf:"bytes,1,opt,name=AttestationResult,proto3" json:"AttestationResult,omitempty"`
}
+48 -8
View File
@@ -26,18 +26,20 @@ const (
)
var (
ErrTEENonceLength = errors.New("malformed report data, expect less or equal to 64 bytes")
ErrVTpmNonceLength = errors.New("malformed vTPM nonce, expect less or equal to 32 bytes")
ErrTEENonceLength = errors.New("malformed report data, expect less or equal to 64 bytes")
ErrVTPMNonceLength = errors.New("malformed vTPM nonce, expect less or equal to 32 bytes")
ErrTokenNonceLength = errors.New("malformed token nonce, expect less or equal to 32 bytes")
)
var _ agent.AgentServiceServer = (*grpcServer)(nil)
type grpcServer struct {
algo grpc.Handler
data grpc.Handler
result grpc.Handler
attestation grpc.Handler
imaMeasurements grpc.Handler
algo grpc.Handler
data grpc.Handler
result grpc.Handler
attestation grpc.Handler
imaMeasurements grpc.Handler
attestationResult grpc.Handler
agent.UnimplementedAgentServiceServer
}
@@ -69,6 +71,11 @@ func NewServer(svc agent.Service) agent.AgentServiceServer {
decodeIMAMeasurementsRequest,
encodeIMAMeasurementsResponse,
),
attestationResult: grpc.NewServer(
attestationResultEndpoint(svc),
decodeAttestationResultRequest,
encodeAttestationResultResponse,
),
}
}
@@ -119,7 +126,7 @@ func decodeAttestationRequest(_ context.Context, grpcReq interface{}) (interface
}
if len(req.VtpmNonce) > vtpm.Nonce {
return nil, ErrVTpmNonceLength
return nil, ErrVTPMNonceLength
}
copy(reportData[:], req.TeeNonce)
@@ -134,6 +141,25 @@ func encodeAttestationResponse(_ context.Context, response interface{}) (interfa
}, nil
}
func encodeAttestationResultResponse(_ context.Context, response interface{}) (interface{}, error) {
res := response.(fetchAttestationResultRes)
return &agent.AttestationResultResponse{
File: res.File,
}, nil
}
func decodeAttestationResultRequest(_ context.Context, grpcReq interface{}) (interface{}, error) {
req := grpcReq.(*agent.AttestationResultRequest)
var nonce [vtpm.Nonce]byte
if len(req.TokenNonce) > vtpm.Nonce {
return nil, ErrVTPMNonceLength
}
copy(nonce[:], req.TokenNonce)
return FetchAttestationResultReq{tokenNonce: nonce, AttType: attestation.PlatformType(req.Type)}, nil
}
// Algo implements agent.AgentServiceServer.
func (s *grpcServer) Algo(stream agent.AgentService_AlgoServer) error {
var algoFile, reqFile []byte
@@ -295,3 +321,17 @@ func (s *grpcServer) IMAMeasurements(req *agent.IMAMeasurementsRequest, stream a
return nil
}
func (s *grpcServer) AttestationResult(ctx context.Context, req *agent.AttestationResultRequest) (*agent.AttestationResultResponse, error) {
_, res, err := s.attestationResult.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
rr, ok := res.(*agent.AttestationResultResponse)
if !ok {
return nil, status.Error(codes.Internal, "failed to cast response to FetchAttestationResultResponse")
}
return rr, nil
}
+29
View File
@@ -165,6 +165,21 @@ func TestAttestation(t *testing.T) {
mockService.AssertExpectations(t)
}
func TestAttestationResult(t *testing.T) {
mockService := new(mocks.Service)
server := NewServer(mockService)
vtpmNonce := [vtpm.Nonce]byte{}
attestationType := attestation.SNP
mockService.On("AttestationResult", mock.Anything, vtpmNonce, attestationType).Return([]byte("attestation data"), nil)
resp, err := server.AttestationResult(context.Background(), &agent.AttestationResultRequest{TokenNonce: vtpmNonce[:]})
assert.NoError(t, err)
assert.Equal(t, []byte("attestation data"), resp.File)
mockService.AssertExpectations(t)
}
func TestDecodeAlgoRequest(t *testing.T) {
req := &agent.AlgoRequest{Algorithm: []byte("algo"), Requirements: []byte("req")}
decoded, err := decodeAlgoRequest(context.Background(), req)
@@ -216,3 +231,17 @@ func TestEncodeAttestationResponse(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, &agent.AttestationResponse{File: []byte("attestation")}, encoded)
}
func TestEncodeAttestationResultResponse(t *testing.T) {
encoded, err := encodeAttestationResultResponse(context.Background(), fetchAttestationResultRes{File: []byte("attestation")})
assert.NoError(t, err)
assert.Equal(t, &agent.AttestationResultResponse{File: []byte("attestation")}, encoded)
}
func TestDecodeAttestationResultRequest(t *testing.T) {
nonce := [vtpm.Nonce]byte{}
req := &agent.AttestationResultRequest{TokenNonce: nonce[:]}
decoded, err := decodeAttestationResultRequest(context.Background(), req)
assert.NoError(t, err)
assert.Equal(t, FetchAttestationResultReq{tokenNonce: nonce}, decoded)
}
+13
View File
@@ -131,3 +131,16 @@ func (lm *loggingMiddleware) IMAMeasurements(ctx context.Context) (file []byte,
return lm.svc.IMAMeasurements(ctx)
}
func (lm *loggingMiddleware) AttestationResult(ctx context.Context, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) (response []byte, err error) {
defer func(begin time.Time) {
message := fmt.Sprintf("Method Attestation took %s to complete", time.Since(begin))
if err != nil {
lm.logger.Warn(fmt.Sprintf("%s with error: %s", message, err))
return
}
lm.logger.Info(fmt.Sprintf("%s without errors", message))
}(time.Now())
return lm.svc.AttestationResult(ctx, nonce, attType)
}
+9
View File
@@ -101,6 +101,15 @@ func (ms *metricsMiddleware) Attestation(ctx context.Context, reportData [quotep
return ms.svc.Attestation(ctx, reportData, nonce, attType)
}
func (ms *metricsMiddleware) AttestationResult(ctx context.Context, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error) {
defer func(begin time.Time) {
ms.counter.With("method", "attestation_result").Add(1)
ms.latency.With("method", "attestation_result").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.AttestationResult(ctx, nonce, attType)
}
func (ms *metricsMiddleware) IMAMeasurements(ctx context.Context) ([]byte, []byte, error) {
defer func(begin time.Time) {
ms.counter.With("method", "imameasurements").Add(1)
+207 -125
View File
@@ -431,6 +431,7 @@ type ClientStreamMessage struct {
// *ClientStreamMessage_StopComputationRes
// *ClientStreamMessage_AgentStateRes
// *ClientStreamMessage_VTPMattestationReport
// *ClientStreamMessage_AzureAttestationResult
Message isClientStreamMessage_Message `protobuf_oneof:"message"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
@@ -527,6 +528,15 @@ func (x *ClientStreamMessage) GetVTPMattestationReport() *AttestationResponse {
return nil
}
func (x *ClientStreamMessage) GetAzureAttestationResult() *AzureAttestationResponse {
if x != nil {
if x, ok := x.Message.(*ClientStreamMessage_AzureAttestationResult); ok {
return x.AzureAttestationResult
}
}
return nil
}
type isClientStreamMessage_Message interface {
isClientStreamMessage_Message()
}
@@ -555,6 +565,10 @@ type ClientStreamMessage_VTPMattestationReport struct {
VTPMattestationReport *AttestationResponse `protobuf:"bytes,6,opt,name=vTPMattestationReport,proto3,oneof"`
}
type ClientStreamMessage_AzureAttestationResult struct {
AzureAttestationResult *AzureAttestationResponse `protobuf:"bytes,7,opt,name=azureAttestationResult,proto3,oneof"`
}
func (*ClientStreamMessage_AgentLog) isClientStreamMessage_Message() {}
func (*ClientStreamMessage_AgentEvent) isClientStreamMessage_Message() {}
@@ -567,6 +581,8 @@ func (*ClientStreamMessage_AgentStateRes) isClientStreamMessage_Message() {}
func (*ClientStreamMessage_VTPMattestationReport) isClientStreamMessage_Message() {}
func (*ClientStreamMessage_AzureAttestationResult) isClientStreamMessage_Message() {}
type ServerStreamMessage struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Message:
@@ -1193,6 +1209,58 @@ func (x *AttestationResponse) GetCertSerialNumber() string {
return ""
}
type AzureAttestationResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
File []byte `protobuf:"bytes,1,opt,name=file,proto3" json:"file,omitempty"`
CertSerialNumber string `protobuf:"bytes,2,opt,name=certSerialNumber,proto3" json:"certSerialNumber,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *AzureAttestationResponse) Reset() {
*x = AzureAttestationResponse{}
mi := &file_agent_cvms_cvms_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *AzureAttestationResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*AzureAttestationResponse) ProtoMessage() {}
func (x *AzureAttestationResponse) ProtoReflect() protoreflect.Message {
mi := &file_agent_cvms_cvms_proto_msgTypes[17]
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 AzureAttestationResponse.ProtoReflect.Descriptor instead.
func (*AzureAttestationResponse) Descriptor() ([]byte, []int) {
return file_agent_cvms_cvms_proto_rawDescGZIP(), []int{17}
}
func (x *AzureAttestationResponse) GetFile() []byte {
if x != nil {
return x.File
}
return nil
}
func (x *AzureAttestationResponse) GetCertSerialNumber() string {
if x != nil {
return x.CertSerialNumber
}
return ""
}
var File_agent_cvms_cvms_proto protoreflect.FileDescriptor
var file_agent_cvms_cvms_proto_rawDesc = string([]byte{
@@ -1243,7 +1311,7 @@ var file_agent_cvms_cvms_proto_rawDesc = string([]byte{
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x93, 0x03, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xed, 0x03, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x2d, 0x0a, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4c,
@@ -1268,92 +1336,103 @@ var file_agent_cvms_cvms_proto_rawDesc = string([]byte{
0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x15, 0x76, 0x54, 0x50,
0x4d, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xca, 0x02,
0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x43,
0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x76,
0x6d, 0x73, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x48,
0x00, 0x52, 0x0c, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12,
0x31, 0x0a, 0x06, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x72, 0x75, 0x6e, 0x52,
0x65, 0x71, 0x12, 0x41, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x76,
0x6d, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74,
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63,
0x76, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65,
0x71, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
0x65, 0x71, 0x12, 0x3b, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
0x52, 0x65, 0x71, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x76, 0x6d, 0x73,
0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00,
0x52, 0x0d, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x42,
0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x69,
0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4b, 0x0a, 0x0c, 0x52,
0x75, 0x6e, 0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64,
0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
0x52, 0x06, 0x69, 0x73, 0x4c, 0x61, 0x73, 0x74, 0x22, 0xaa, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6d,
0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73,
0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x44, 0x61,
0x74, 0x61, 0x73, 0x65, 0x74, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12,
0x2d, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69,
0x74, 0x68, 0x6d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x3f,
0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x0f,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x12,
0x34, 0x0a, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18,
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x65,
0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x2a, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43,
0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65,
0x79, 0x22, 0x53, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68,
0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69,
0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69,
0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x39, 0x0a, 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69,
0x74, 0x68, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b,
0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65,
0x79, 0x22, 0xe5, 0x01, 0x0a, 0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69,
0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a,
0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x46,
0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x61,
0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72,
0x76, 0x65, 0x72, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67,
0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f,
0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74,
0x65, 0x64, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x74,
0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x6c, 0x73, 0x22, 0x55, 0x0a, 0x13, 0x41, 0x74, 0x74,
0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x65, 0x72, 0x69,
0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10,
0x63, 0x65, 0x72, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x32, 0x50, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x07, 0x50,
0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x19, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x43, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x1a, 0x19, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01,
0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x63, 0x76, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x72, 0x74, 0x12, 0x58, 0x0a, 0x16, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x07, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x41,
0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x48, 0x00, 0x52, 0x16, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x42, 0x09, 0x0a, 0x07,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x38, 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x52, 0x75, 0x6e,
0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x75, 0x6e,
0x52, 0x65, 0x71, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x75, 0x6e,
0x52, 0x65, 0x71, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x76, 0x6d, 0x73,
0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52,
0x65, 0x71, 0x48, 0x00, 0x52, 0x06, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x41, 0x0a, 0x0f,
0x73, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x53, 0x74, 0x6f,
0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f,
0x73, 0x74, 0x6f, 0x70, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x3b, 0x0a, 0x0d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x67,
0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x61,
0x67, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x12, 0x3b, 0x0a, 0x0d,
0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x18, 0x05, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f,
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x63,
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
0x63, 0x74, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4b, 0x0a, 0x0c, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x43,
0x68, 0x75, 0x6e, 0x6b, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f,
0x6c, 0x61, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4c, 0x61,
0x73, 0x74, 0x22, 0xaa, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b,
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29,
0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x0d, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x52,
0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x09, 0x61, 0x6c, 0x67,
0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63,
0x76, 0x6d, 0x73, 0x2e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, 0x09, 0x61,
0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x3f, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x0c, 0x61, 0x67, 0x65,
0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x11, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x52, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
0x2a, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65,
0x72, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x22, 0x53, 0x0a, 0x07, 0x44,
0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73,
0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x75, 0x73, 0x65,
0x72, 0x4b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
0x22, 0x39, 0x0a, 0x09, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x12, 0x0a,
0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73,
0x68, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x07, 0x75, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x22, 0xe5, 0x01, 0x0a, 0x0b,
0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70,
0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12,
0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x63, 0x65, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08,
0x6b, 0x65, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x6b, 0x65, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a,
0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18,
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x46,
0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c,
0x12, 0x21, 0x0a, 0x0c, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6c, 0x73,
0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64,
0x54, 0x6c, 0x73, 0x22, 0x55, 0x0a, 0x13, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a,
0x0a, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x65,
0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x5a, 0x0a, 0x18, 0x61, 0x7a,
0x75, 0x72, 0x65, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x65,
0x72, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x65, 0x72, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c,
0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x32, 0x50, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x45, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x19, 0x2e, 0x63,
0x76, 0x6d, 0x73, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, 0x2e, 0x63, 0x76, 0x6d, 0x73, 0x2e, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x63, 0x76,
0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
})
var (
@@ -1368,52 +1447,54 @@ func file_agent_cvms_cvms_proto_rawDescGZIP() []byte {
return file_agent_cvms_cvms_proto_rawDescData
}
var file_agent_cvms_cvms_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
var file_agent_cvms_cvms_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
var file_agent_cvms_cvms_proto_goTypes = []any{
(*AgentStateReq)(nil), // 0: cvms.AgentStateReq
(*AgentStateRes)(nil), // 1: cvms.AgentStateRes
(*StopComputation)(nil), // 2: cvms.StopComputation
(*StopComputationResponse)(nil), // 3: cvms.StopComputationResponse
(*RunResponse)(nil), // 4: cvms.RunResponse
(*AgentEvent)(nil), // 5: cvms.AgentEvent
(*AgentLog)(nil), // 6: cvms.AgentLog
(*ClientStreamMessage)(nil), // 7: cvms.ClientStreamMessage
(*ServerStreamMessage)(nil), // 8: cvms.ServerStreamMessage
(*DisconnectReq)(nil), // 9: cvms.DisconnectReq
(*RunReqChunks)(nil), // 10: cvms.RunReqChunks
(*ComputationRunReq)(nil), // 11: cvms.ComputationRunReq
(*ResultConsumer)(nil), // 12: cvms.ResultConsumer
(*Dataset)(nil), // 13: cvms.Dataset
(*Algorithm)(nil), // 14: cvms.Algorithm
(*AgentConfig)(nil), // 15: cvms.AgentConfig
(*AttestationResponse)(nil), // 16: cvms.AttestationResponse
(*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp
(*AgentStateReq)(nil), // 0: cvms.AgentStateReq
(*AgentStateRes)(nil), // 1: cvms.AgentStateRes
(*StopComputation)(nil), // 2: cvms.StopComputation
(*StopComputationResponse)(nil), // 3: cvms.StopComputationResponse
(*RunResponse)(nil), // 4: cvms.RunResponse
(*AgentEvent)(nil), // 5: cvms.AgentEvent
(*AgentLog)(nil), // 6: cvms.AgentLog
(*ClientStreamMessage)(nil), // 7: cvms.ClientStreamMessage
(*ServerStreamMessage)(nil), // 8: cvms.ServerStreamMessage
(*DisconnectReq)(nil), // 9: cvms.DisconnectReq
(*RunReqChunks)(nil), // 10: cvms.RunReqChunks
(*ComputationRunReq)(nil), // 11: cvms.ComputationRunReq
(*ResultConsumer)(nil), // 12: cvms.ResultConsumer
(*Dataset)(nil), // 13: cvms.Dataset
(*Algorithm)(nil), // 14: cvms.Algorithm
(*AgentConfig)(nil), // 15: cvms.AgentConfig
(*AttestationResponse)(nil), // 16: cvms.AttestationResponse
(*AzureAttestationResponse)(nil), // 17: cvms.azureAttestationResponse
(*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp
}
var file_agent_cvms_cvms_proto_depIdxs = []int32{
17, // 0: cvms.AgentEvent.timestamp:type_name -> google.protobuf.Timestamp
17, // 1: cvms.AgentLog.timestamp:type_name -> google.protobuf.Timestamp
18, // 0: cvms.AgentEvent.timestamp:type_name -> google.protobuf.Timestamp
18, // 1: cvms.AgentLog.timestamp:type_name -> google.protobuf.Timestamp
6, // 2: cvms.ClientStreamMessage.agent_log:type_name -> cvms.AgentLog
5, // 3: cvms.ClientStreamMessage.agent_event:type_name -> cvms.AgentEvent
4, // 4: cvms.ClientStreamMessage.run_res:type_name -> cvms.RunResponse
3, // 5: cvms.ClientStreamMessage.stopComputationRes:type_name -> cvms.StopComputationResponse
1, // 6: cvms.ClientStreamMessage.agentStateRes:type_name -> cvms.AgentStateRes
16, // 7: cvms.ClientStreamMessage.vTPMattestationReport:type_name -> cvms.AttestationResponse
10, // 8: cvms.ServerStreamMessage.runReqChunks:type_name -> cvms.RunReqChunks
11, // 9: cvms.ServerStreamMessage.runReq:type_name -> cvms.ComputationRunReq
2, // 10: cvms.ServerStreamMessage.stopComputation:type_name -> cvms.StopComputation
0, // 11: cvms.ServerStreamMessage.agentStateReq:type_name -> cvms.AgentStateReq
9, // 12: cvms.ServerStreamMessage.disconnectReq:type_name -> cvms.DisconnectReq
13, // 13: cvms.ComputationRunReq.datasets:type_name -> cvms.Dataset
14, // 14: cvms.ComputationRunReq.algorithm:type_name -> cvms.Algorithm
12, // 15: cvms.ComputationRunReq.result_consumers:type_name -> cvms.ResultConsumer
15, // 16: cvms.ComputationRunReq.agent_config:type_name -> cvms.AgentConfig
7, // 17: cvms.Service.Process:input_type -> cvms.ClientStreamMessage
8, // 18: cvms.Service.Process:output_type -> cvms.ServerStreamMessage
18, // [18:19] is the sub-list for method output_type
17, // [17:18] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
17, // 8: cvms.ClientStreamMessage.azureAttestationResult:type_name -> cvms.azureAttestationResponse
10, // 9: cvms.ServerStreamMessage.runReqChunks:type_name -> cvms.RunReqChunks
11, // 10: cvms.ServerStreamMessage.runReq:type_name -> cvms.ComputationRunReq
2, // 11: cvms.ServerStreamMessage.stopComputation:type_name -> cvms.StopComputation
0, // 12: cvms.ServerStreamMessage.agentStateReq:type_name -> cvms.AgentStateReq
9, // 13: cvms.ServerStreamMessage.disconnectReq:type_name -> cvms.DisconnectReq
13, // 14: cvms.ComputationRunReq.datasets:type_name -> cvms.Dataset
14, // 15: cvms.ComputationRunReq.algorithm:type_name -> cvms.Algorithm
12, // 16: cvms.ComputationRunReq.result_consumers:type_name -> cvms.ResultConsumer
15, // 17: cvms.ComputationRunReq.agent_config:type_name -> cvms.AgentConfig
7, // 18: cvms.Service.Process:input_type -> cvms.ClientStreamMessage
8, // 19: cvms.Service.Process:output_type -> cvms.ServerStreamMessage
19, // [19:20] is the sub-list for method output_type
18, // [18:19] is the sub-list for method input_type
18, // [18:18] is the sub-list for extension type_name
18, // [18:18] is the sub-list for extension extendee
0, // [0:18] is the sub-list for field type_name
}
func init() { file_agent_cvms_cvms_proto_init() }
@@ -1428,6 +1509,7 @@ func file_agent_cvms_cvms_proto_init() {
(*ClientStreamMessage_StopComputationRes)(nil),
(*ClientStreamMessage_AgentStateRes)(nil),
(*ClientStreamMessage_VTPMattestationReport)(nil),
(*ClientStreamMessage_AzureAttestationResult)(nil),
}
file_agent_cvms_cvms_proto_msgTypes[8].OneofWrappers = []any{
(*ServerStreamMessage_RunReqChunks)(nil),
@@ -1442,7 +1524,7 @@ func file_agent_cvms_cvms_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_agent_cvms_cvms_proto_rawDesc), len(file_agent_cvms_cvms_proto_rawDesc)),
NumEnums: 0,
NumMessages: 17,
NumMessages: 18,
NumExtensions: 0,
NumServices: 1,
},
+6
View File
@@ -60,6 +60,7 @@ message ClientStreamMessage {
StopComputationResponse stopComputationRes = 4;
AgentStateRes agentStateRes = 5;
AttestationResponse vTPMattestationReport = 6;
azureAttestationResponse azureAttestationResult = 7;
}
}
@@ -122,3 +123,8 @@ message AttestationResponse {
bytes file = 1;
string certSerialNumber = 2;
}
message azureAttestationResponse {
bytes file = 1;
string certSerialNumber = 2;
}
+60
View File
@@ -135,6 +135,66 @@ func (_c *Service_Attestation_Call) RunAndReturn(run func(context.Context, [64]b
return _c
}
// AttestationResult provides a mock function with given fields: ctx, nonce, attType
func (_m *Service) AttestationResult(ctx context.Context, nonce [32]byte, attType attestation.PlatformType) ([]byte, error) {
ret := _m.Called(ctx, nonce, attType)
if len(ret) == 0 {
panic("no return value specified for AttestationResult")
}
var r0 []byte
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, [32]byte, attestation.PlatformType) ([]byte, error)); ok {
return rf(ctx, nonce, attType)
}
if rf, ok := ret.Get(0).(func(context.Context, [32]byte, attestation.PlatformType) []byte); ok {
r0 = rf(ctx, nonce, attType)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
if rf, ok := ret.Get(1).(func(context.Context, [32]byte, attestation.PlatformType) error); ok {
r1 = rf(ctx, nonce, attType)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Service_AttestationResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AttestationResult'
type Service_AttestationResult_Call struct {
*mock.Call
}
// AttestationResult is a helper method to define mock.On call
// - ctx context.Context
// - nonce [32]byte
// - attType attestation.PlatformType
func (_e *Service_Expecter) AttestationResult(ctx interface{}, nonce interface{}, attType interface{}) *Service_AttestationResult_Call {
return &Service_AttestationResult_Call{Call: _e.mock.On("AttestationResult", ctx, nonce, attType)}
}
func (_c *Service_AttestationResult_Call) Run(run func(ctx context.Context, nonce [32]byte, attType attestation.PlatformType)) *Service_AttestationResult_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].([32]byte), args[2].(attestation.PlatformType))
})
return _c
}
func (_c *Service_AttestationResult_Call) Return(_a0 []byte, _a1 error) *Service_AttestationResult_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *Service_AttestationResult_Call) RunAndReturn(run func(context.Context, [32]byte, attestation.PlatformType) ([]byte, error)) *Service_AttestationResult_Call {
_c.Call.Return(run)
return _c
}
// Data provides a mock function with given fields: ctx, dataset
func (_m *Service) Data(ctx context.Context, dataset agent.Dataset) error {
ret := _m.Called(ctx, dataset)
+16
View File
@@ -106,6 +106,8 @@ var (
ErrAttestationFailed = errors.New("failed to get raw quote")
// ErrAttestationVTpmFailed vTPM attestation failed.
ErrAttestationVTpmFailed = errors.New("failed to get vTPM quote")
// ErrFetchAzureToken azure token fetch failed.
ErrFetchAzureToken = errors.New("failed to get azure token")
// 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")
)
@@ -120,6 +122,7 @@ type Service interface {
Result(ctx context.Context) ([]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)
AttestationResult(ctx context.Context, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error)
State() string
}
@@ -447,6 +450,19 @@ func (as *agentService) Attestation(ctx context.Context, reportData [quoteprovid
}
}
func (as *agentService) AttestationResult(ctx context.Context, nonce [vtpm.Nonce]byte, attType attestation.PlatformType) ([]byte, error) {
switch attType {
case attestation.AzureToken:
token, err := as.provider.AzureAttestationToken(nonce[:])
if err != nil {
return []byte{}, err
}
return token, nil
default:
return []byte{}, ErrAttestationType
}
}
func (as *agentService) runComputation(state statemachine.State) {
as.publishEvent(Starting.String())(state)
as.logger.Debug("computation run started")
+52
View File
@@ -400,6 +400,58 @@ func TestAttestation(t *testing.T) {
}
}
func TestAttestationResult(t *testing.T) {
provider := new(mocks2.Provider)
cases := []struct {
name string
nonce [vtpm.Nonce]byte
platform attestation.PlatformType
token []byte
err error
}{
{
name: "Azure token fetch successful",
nonce: [32]byte{1, 2, 3}, // any test nonce
platform: attestation.AzureToken,
token: []byte("mockToken"),
err: nil,
},
{
name: "Azure token fetch failed",
nonce: [32]byte{4, 5, 6},
platform: attestation.AzureToken,
token: []byte{},
err: ErrFetchAzureToken,
},
{
name: "Invalid attestation type",
nonce: [32]byte{7, 8, 9},
platform: attestation.SNP,
token: []byte{},
err: ErrAttestationType,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
events := new(mocks.Service)
events.EXPECT().SendEvent(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return()
if tc.platform == attestation.AzureToken {
provider.On("AzureAttestationToken", tc.nonce[:]).Return(tc.token, tc.err)
}
ctx := context.Background()
svc := New(ctx, mglog.NewMock(), events, provider, 0)
result, err := svc.AttestationResult(ctx, tc.nonce, tc.platform)
assert.True(t, errors.Contains(err, tc.err), "expected error %v, got %v", tc.err, err)
assert.Equal(t, tc.token, result)
})
}
}
func generateReportData() [quoteprovider.Nonce]byte {
bytes := make([]byte, quoteprovider.Nonce)
_, err := rand.Read(bytes)
+167 -76
View File
@@ -3,6 +3,7 @@
package cli
import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
@@ -32,29 +33,31 @@ import (
)
const (
defaultMinimumTcb = 0
defaultMinimumLaunchTcb = 0
defaultMinimumGuestSvn = 0
defaultGuestPolicy = 0x0000000000030000
defaultMinimumBuild = 0
defaultCheckCrl = false
defaultTimeout = 2 * time.Minute
defaultMaxRetryDelay = 30 * time.Second
defaultRequireAuthor = false
defaultRequireIdBlock = false
defaultMinVersion = "0.0"
size16 = 16
size32 = 32
size48 = 48
size64 = 64
attestationFilePath = "attestation.bin"
vtpmFilePath = "../quote.dat"
attestationJson = "attestation.json"
sevProductNameMilan = "Milan"
sevProductNameGenoa = "Genoa"
FormatBinaryPB = "binarypb"
FormatTextProto = "textproto"
exampleJSONConfig = `
defaultMinimumTcb = 0
defaultMinimumLaunchTcb = 0
defaultMinimumGuestSvn = 0
defaultGuestPolicy = 0x0000000000030000
defaultMinimumBuild = 0
defaultCheckCrl = false
defaultTimeout = 2 * time.Minute
defaultMaxRetryDelay = 30 * time.Second
defaultRequireAuthor = false
defaultRequireIdBlock = false
defaultMinVersion = "0.0"
size16 = 16
size32 = 32
size48 = 48
size64 = 64
attestationFilePath = "attestation.bin"
azureAttestResultFilePath = "azure_attest_result.json"
azureAttestTokenFilePath = "azure_attest_token.jwt"
vtpmFilePath = "../quote.dat"
attestationReportJson = "attestation.json"
sevProductNameMilan = "Milan"
sevProductNameGenoa = "Genoa"
FormatBinaryPB = "binarypb"
FormatTextProto = "textproto"
exampleJSONConfig = `
{
"rootOfTrust":{
"product":"test_product",
@@ -107,41 +110,44 @@ const (
}
}
`
SNP = "snp"
VTPM = "vtpm"
SNPvTPM = "snp-vtpm"
CCNone = "none"
CCAzure = "azure"
CCGCP = "gcp"
SNP = "snp"
VTPM = "vtpm"
SNPvTPM = "snp-vtpm"
AzureToken = "azure-token"
CCNone = "none"
CCAzure = "azure"
CCGCP = "gcp"
)
var (
mode string
cfg = check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}
cfgString string
timeout time.Duration
maxRetryDelay time.Duration
platformInfo string
stepping string
trustedAuthorKeys []string
trustedAuthorHashes []string
trustedIdKeys []string
trustedIdKeyHashes []string
attestationFile string
tpmAttestationFile string
attestationRaw []byte
empty16 = [size16]byte{}
empty32 = [size32]byte{}
empty64 = [size64]byte{}
defaultReportIdMa = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
errReportSize = errors.New("attestation contents too small")
ErrBadAttestation = errors.New("attestation file is corrupted or in wrong format")
output string
nonce []byte
format string
teeNonce []byte
getTextProtoAttestation bool
cloud string
mode string
cfg = check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}
cfgString string
timeout time.Duration
maxRetryDelay time.Duration
platformInfo string
stepping string
trustedAuthorKeys []string
trustedAuthorHashes []string
trustedIdKeys []string
trustedIdKeyHashes []string
attestationFile string
tpmAttestationFile string
attestationRaw []byte
empty16 = [size16]byte{}
empty32 = [size32]byte{}
empty64 = [size64]byte{}
defaultReportIdMa = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
errReportSize = errors.New("attestation contents too small")
ErrBadAttestation = errors.New("attestation file is corrupted or in wrong format")
output string
nonce []byte
format string
teeNonce []byte
tokenNonce []byte
getTextProtoAttestationReport bool
getAzureTokenJWT bool
cloud string
)
var errEmptyFile = errors.New("input file is empty")
@@ -180,11 +186,12 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Short: "Retrieve attestation information from agent. The argument of the command must be the type of the report (snp or vtpm or snp-vtpm).",
ValidArgs: []cobra.Completion{SNP, VTPM, SNPvTPM},
ValidArgs: []cobra.Completion{SNP, VTPM, SNPvTPM, AzureToken},
Example: fmt.Sprintf(`Based on attestation report type:
get %s --tee <512 bit hex value>
get %s --vtpm <256 bit hex value>
get %s --tee <512 bit hex value> --vtpm <256 bit hex value>`, SNP, VTPM, SNPvTPM),
get %s --tee <512 bit hex value> --vtpm <256 bit hex value>
get %s --token <256 bit hex value>`, SNP, VTPM, SNPvTPM, AzureToken),
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
if cli.connectErr != nil {
@@ -209,6 +216,9 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
case SNPvTPM:
cmd.Println("Fetching SEV-SNP and vTPM report")
attType = attestation.SNPvTPM
case AzureToken:
cmd.Println("Fetching Azure token")
attType = attestation.AzureToken
}
if (attType == attestation.VTPM || attType == attestation.SNPvTPM) && len(nonce) == 0 {
@@ -223,8 +233,14 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
return
}
if (attType == attestation.AzureToken) && len(tokenNonce) == 0 {
msg := color.New(color.FgRed).Sprint("Token nonce must be defined for Azure attestation ❌ ")
cmd.Println(msg)
return
}
var fixedReportData [quoteprovider.Nonce]byte
if attType != attestation.VTPM {
if attType == attestation.SNP || attType == attestation.SNPvTPM {
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)
cmd.Println(msg)
@@ -236,18 +252,28 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
var fixedVtpmNonceByte [vtpm.Nonce]byte
if attType != attestation.SNP {
if len(nonce) > vtpm.Nonce {
if (len(nonce) > vtpm.Nonce) || (len(tokenNonce) > 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)
return
}
copy(fixedVtpmNonceByte[:], nonce)
if attType == attestation.AzureToken {
copy(fixedVtpmNonceByte[:], tokenNonce)
} else {
copy(fixedVtpmNonceByte[:], nonce)
}
}
filename := attestationFilePath
if getTextProtoAttestation {
filename = attestationJson
if attType == attestation.AzureToken {
filename = azureAttestResultFilePath
}
if getTextProtoAttestationReport {
filename = attestationReportJson
} else if getAzureTokenJWT {
filename = azureAttestTokenFilePath
}
attestationFile, err := os.Create(filename)
@@ -256,9 +282,21 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
return
}
if err := cli.agentSDK.Attestation(cmd.Context(), fixedReportData, fixedVtpmNonceByte, int(attType), attestationFile); err != nil {
printError(cmd, "Failed to get attestation due to error: %v ❌ ", err)
return
var returnJsonAzureToken bool
if attType == attestation.AzureToken {
err := cli.agentSDK.AttestationResult(cmd.Context(), fixedVtpmNonceByte, int(attType), attestationFile)
if err != nil {
printError(cmd, "Failed to get attestation result due to error: %v ❌", err)
return
}
returnJsonAzureToken = !getAzureTokenJWT
} else {
err := cli.agentSDK.Attestation(cmd.Context(), fixedReportData, fixedVtpmNonceByte, int(attType), attestationFile)
if err != nil {
printError(cmd, "Failed to get attestation due to error: %v ❌", err)
return
}
}
if err := attestationFile.Close(); err != nil {
@@ -266,7 +304,7 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
return
}
if getTextProtoAttestation {
if getTextProtoAttestationReport || returnJsonAzureToken {
result, err := os.ReadFile(filename)
if err != nil {
printError(cmd, "Error reading attestation file: %v ❌ ", err)
@@ -276,6 +314,11 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
switch attestationType {
case SNP:
result, err = attesationToJSON(result)
if err != nil {
printError(cmd, "Error converting SNP attestation to JSON: %v ❌", err)
return
}
case VTPM, SNPvTPM:
marshalOptions := prototext.MarshalOptions{
Multiline: true,
@@ -284,15 +327,17 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
var attvTPM tpmAttest.Attestation
err = proto.Unmarshal(result, &attvTPM)
if err != nil {
printError(cmd, "failed to unmarshal the attestation report: %v ❌ ", ErrBadAttestation)
printError(cmd, "Failed to unmarshal the attestation report: %v ❌", err)
return
}
result = []byte(marshalOptions.Format(&attvTPM))
}
if err != nil {
printError(cmd, "Error converting attestation to textproto: %v ❌ ", err)
return
case AzureToken:
result, err = decodeJWTToJSON(result)
if err != nil {
printError(cmd, "Error decoding Azure token: %v ❌", err)
return
}
}
if err := os.WriteFile(filename, result, 0o644); err != nil {
@@ -305,9 +350,11 @@ func (cli *CLI) NewGetAttestationCmd() *cobra.Command {
},
}
cmd.Flags().BoolVarP(&getTextProtoAttestation, "textproto", "p", false, "Get attestation in textproto format")
cmd.Flags().BytesHexVarP(&teeNonce, "tee", "e", []byte{}, "Define the nonce for the SNP attestation report (must be used with attestation type snp and snp-vtpm)")
cmd.Flags().BytesHexVarP(&nonce, "vtpm", "t", []byte{}, "Define the nonce for the vTPM attestation report (must be used with attestation type vtpm and snp-vtpm)")
cmd.Flags().BoolVarP(&getAzureTokenJWT, "azurejwt", "t", false, "Get azure attestation token as jwt format")
cmd.Flags().BoolVarP(&getTextProtoAttestationReport, "reporttextproto", "r", false, "Get attestation report in textproto format")
cmd.Flags().BytesHexVar(&teeNonce, "tee", []byte{}, "Define the nonce for the SNP attestation report (must be used with attestation type snp and snp-vtpm)")
cmd.Flags().BytesHexVar(&nonce, "vtpm", []byte{}, "Define the nonce for the vTPM attestation report (must be used with attestation type vtpm and snp-vtpm)")
cmd.Flags().BytesHexVar(&tokenNonce, "token", []byte{}, "Define the nonce for the Azure attestation token (must be used with attestation type azure-token)")
return cmd
}
@@ -1036,3 +1083,47 @@ func validateFieldLength(fieldName string, field []byte, expectedLength int) err
}
return nil
}
func decodeJWTToJSON(tokenBytes []byte) ([]byte, error) {
token := string(tokenBytes) // convert to string
parts := strings.Split(token, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("invalid JWT: must have at least 2 parts")
}
decode := func(seg string) (map[string]interface{}, error) {
// Add padding if missing
if m := len(seg) % 4; m != 0 {
seg += strings.Repeat("=", 4-m)
}
data, err := base64.URLEncoding.DecodeString(seg)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(data, &result); err != nil {
return nil, err
}
return result, nil
}
header, err := decode(parts[0])
if err != nil {
return nil, fmt.Errorf("failed to decode header: %v", err)
}
payload, err := decode(parts[1])
if err != nil {
return nil, fmt.Errorf("failed to decode payload: %v", err)
}
combined := map[string]interface{}{
"header": header,
"payload": payload,
}
return json.MarshalIndent(combined, "", " ")
}
+87 -7
View File
@@ -49,6 +49,7 @@ func TestNewGetAttestationCmd(t *testing.T) {
teeNonce := hex.EncodeToString(bytes.Repeat([]byte{0x00}, quoteprovider.Nonce))
vtpmNonce := hex.EncodeToString(bytes.Repeat([]byte{0x00}, vtpm.Nonce))
tokenNonce := hex.EncodeToString(bytes.Repeat([]byte{0x00}, vtpm.Nonce))
testCases := []struct {
name string
@@ -102,7 +103,7 @@ func TestNewGetAttestationCmd(t *testing.T) {
},
{
name: "invalid vTPM data size",
args: []string{"vtpm", "-t", hex.EncodeToString(bytes.Repeat([]byte{0x00}, 33))},
args: []string{"vtpm", "--vtpm", hex.EncodeToString(bytes.Repeat([]byte{0x00}, 33))},
mockResponse: nil,
mockError: errors.New("error"),
expectedErr: "vTPM nonce must be a hex encoded string of length lesser or equal 32 bytes",
@@ -116,39 +117,60 @@ func TestNewGetAttestationCmd(t *testing.T) {
},
{
name: "failed to get attestation",
args: []string{"snp", "-e", teeNonce},
args: []string{"snp", "--tee", teeNonce},
mockResponse: nil,
mockError: errors.New("error"),
expectedErr: "Failed to get attestation due to error",
},
{
name: "Textproto report error",
args: []string{"snp", "-e", teeNonce, "--textproto"},
args: []string{"snp", "--tee", teeNonce, "--reporttextproto"},
mockResponse: []byte("mock attestation"),
mockError: nil,
expectedErr: "Error converting attestation to textproto",
expectedErr: "Fetching SEV-SNP attestation report\nError converting SNP attestation to JSON: attestation contents too small : attestation contents too small (0x10 bytes). Want at least 0x4a0 bytes ❌\n",
},
{
name: "successful Textproto report",
args: []string{"snp", "-e", teeNonce, "--textproto"},
args: []string{"snp", "--tee", teeNonce, "--reporttextproto"},
mockResponse: validattestation,
mockError: nil,
expectedOut: "Attestation result retrieved and saved successfully!",
},
{
name: "connection error",
args: []string{"snp", "-e", teeNonce},
args: []string{"snp", "--tee", teeNonce},
mockResponse: nil,
mockError: errors.New("failed to connect to agent"),
expectedErr: "Failed to connect to agent",
},
{
name: "successful Azure token retrieval",
args: []string{"azure-token", "--token", tokenNonce},
mockResponse: []byte("eyJhbGciOiAiUlMyNTYifQ.eyJzdWIiOiAidGVzdC11c2VyIn0.signature"),
mockError: nil,
expectedOut: "Fetching Azure token\nAttestation result retrieved and saved successfully!\n",
},
{
name: "failed to retrieve Azure token",
args: []string{"azure-token", "--token", tokenNonce},
mockResponse: nil,
mockError: errors.New("error"),
expectedErr: "Fetching Azure token\nFailed to get attestation result due to error: error ❌\n",
},
{
name: "invalid token nonce size",
args: []string{"azure-token", "--token", hex.EncodeToString(bytes.Repeat([]byte{0x00}, 33))},
mockResponse: nil,
mockError: errors.New("error"),
expectedErr: "Fetching Azure token\nvTPM nonce must be a hex encoded string of length lesser or equal 32 bytes ❌ \n",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Cleanup(func() {
os.Remove(attestationFilePath)
os.Remove(attestationJson)
os.Remove(attestationReportJson)
})
mockSDK := new(mocks.SDK)
cli := &CLI{agentSDK: mockSDK}
@@ -164,6 +186,11 @@ func TestNewGetAttestationCmd(t *testing.T) {
require.NoError(t, err)
})
mockSDK.On("AttestationResult", mock.Anything, [vtpm.Nonce]byte(bytes.Repeat([]byte{0x00}, vtpm.Nonce)), mock.Anything, mock.Anything).Return(tc.mockError).Run(func(args mock.Arguments) {
_, err := args.Get(3).(*os.File).Write(tc.mockResponse)
require.NoError(t, err)
})
cmd.SetArgs(tc.args)
err := cmd.Execute()
@@ -627,3 +654,56 @@ func TestRoundTrip(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, roundTripReport)
}
func TestDecodeJWTToJSON(t *testing.T) {
tests := []struct {
name string
input []byte
err error
validate func(t *testing.T, output []byte)
}{
{
name: "Valid JWT",
input: []byte("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ." +
"SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"),
err: nil,
validate: func(t *testing.T, output []byte) {
assert.NotEmpty(t, output)
assert.Contains(t, string(output), `"header"`)
assert.Contains(t, string(output), `"payload"`)
},
},
{
name: "Invalid JWT - one part",
input: []byte("justonepart"),
err: fmt.Errorf("invalid JWT: must have at least 2 parts"),
validate: func(t *testing.T, output []byte) {
assert.Nil(t, output)
},
},
{
name: "Invalid Base64",
input: []byte("bad@@@.header"),
err: errors.New("illegal base64 data"),
validate: func(t *testing.T, output []byte) {
assert.Nil(t, output)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := decodeJWTToJSON(tt.input)
if tt.err != nil {
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.err.Error())
} else {
assert.NoError(t, err)
}
tt.validate(t, got)
})
}
}
+49 -5
View File
@@ -19,7 +19,6 @@ import (
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/prometheus"
"github.com/caarlos0/env/v11"
"github.com/edgelesssys/go-azguestattestation/maa"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/agent/api"
"github.com/ultravioletrs/cocos/agent/cvms"
@@ -89,6 +88,14 @@ func main() {
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.New(nil, false, uint(cfg.Vmpl), nil)
@@ -144,10 +151,6 @@ func main() {
return
}
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 {
@@ -189,6 +192,13 @@ func main() {
return
}
azureAttestationResult, azureCertSerialNumber, err := azureAttestationFromCert(ctx, cvmGrpcConfig.ClientCert, svc)
if err != nil {
logger.Error(fmt.Sprintf("failed to get attestation: %s", err))
exitCode = 1
return
}
eventsLogsQueue <- &cvms.ClientStreamMessage{
Message: &cvms.ClientStreamMessage_VTPMattestationReport{
VTPMattestationReport: &cvms.AttestationResponse{
@@ -198,6 +208,15 @@ func main() {
},
}
eventsLogsQueue <- &cvms.ClientStreamMessage{
Message: &cvms.ClientStreamMessage_AzureAttestationResult{
AzureAttestationResult: &cvms.AzureAttestationResponse{
File: azureAttestationResult,
CertSerialNumber: azureCertSerialNumber,
},
},
}
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}
@@ -238,3 +257,28 @@ func attestationFromCert(ctx context.Context, certFilePath string, svc agent.Ser
return attest, certx509.SerialNumber.String(), nil
}
func azureAttestationFromCert(ctx context.Context, certFilePath string, svc agent.Service) ([]byte, string, error) {
if certFilePath == "" {
return nil, "", nil
}
certFile, err := os.ReadFile(certFilePath)
if err != nil {
return nil, "", err
}
certPem, _ := pem.Decode(certFile)
certx509, err := x509.ParseCertificate(certPem.Bytes)
if err != nil {
return nil, "", err
}
nonceAzure := sha256.Sum256(certFile)
attestation, err := svc.AttestationResult(ctx, nonceAzure, attestation.AzureToken)
if err != nil {
return nil, "", err
}
return attestation, certx509.SerialNumber.String(), nil
}
+11 -4
View File
@@ -26,8 +26,9 @@ require (
)
require (
cloud.google.com/go/compute/metadata v0.6.0
cloud.google.com/go/storage v1.51.0
github.com/edgelesssys/go-azguestattestation v0.0.0-20250408071817-8c4457b235ff
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/gce-tcb-verifier v0.3.1
)
@@ -37,7 +38,7 @@ require (
cloud.google.com/go v0.118.3 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/confidentialcomputing v1.8.0 // indirect
cloud.google.com/go/iam v1.4.1 // indirect
cloud.google.com/go/monitoring v1.24.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
@@ -46,7 +47,9 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
github.com/containerd/errdefs v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
@@ -56,6 +59,7 @@ require (
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/gofrs/uuid/v5 v5.3.0 // 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/go-attestation v0.5.1 // indirect
github.com/google/go-eventlog v0.0.2-0.20241003021507-01bb555f7cba // indirect
@@ -73,6 +77,7 @@ require (
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
@@ -95,16 +100,18 @@ require (
github.com/absmach/certs v0.0.0-20250313105043-afbcda9a9963
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/containerd v1.7.27
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/docker/docker v28.0.1+incompatible
github.com/docker/docker v28.0.4+incompatible
github.com/edgelesssys/go-azguestattestation v0.0.0-20250408071817-8c4457b235ff
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.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-tpm v0.9.3
github.com/google/go-tpm-tools v0.4.4
github.com/google/go-tpm-tools/verifier v0.0.0-20250401045350-423d6a29a6d4
github.com/google/logger v1.1.1
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
+16 -2
View File
@@ -8,6 +8,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
cloud.google.com/go/confidentialcomputing v1.8.0 h1:Ww6t7uhIqC21N+nFTRzb+UJbXRp6bBhhY3bGxc5mK/Y=
cloud.google.com/go/confidentialcomputing v1.8.0/go.mod h1:XxFLLdm6WINyCXqpFDJArVYThgtgD3yHmbhteIJADgQ=
cloud.google.com/go/iam v1.4.1 h1:cFC25Nv+u5BkTR/BT1tXdoF2daiVbZ1RLx2eqfQ9RMM=
cloud.google.com/go/iam v1.4.1/go.mod h1:2vUEJpUG3Q9p2UdsyksaKpDzlwOrnMzS30isdReIcLM=
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
@@ -48,18 +50,25 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/danko-miladinovic/go-tpm-tools v0.0.0-20250228160324-1ebcfd79567c h1:gFo8kqRXFoM6ttqMrK+M3xffxco+Yj80kUo3NoMe8LU=
github.com/danko-miladinovic/go-tpm-tools v0.0.0-20250228160324-1ebcfd79567c/go.mod h1:ktjTNq8yZFD6TzdBFefUfen96rF3NpYwpSb2d8bc+Y8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0=
github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -101,6 +110,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -125,6 +136,8 @@ github.com/google/go-tdx-guest v0.3.2-0.20241009005452-097ee70d0843 h1:+MoPobRN9
github.com/google/go-tdx-guest v0.3.2-0.20241009005452-097ee70d0843/go.mod h1:g/n8sKITIT9xRivBUbizo34DTsUm2nN2uU3A662h09g=
github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc=
github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/go-tpm-tools/verifier v0.0.0-20250401045350-423d6a29a6d4 h1:prG49QOVZnUgzHBEXEVpqRWwI1WpgPm75NG/iVPQM4g=
github.com/google/go-tpm-tools/verifier v0.0.0-20250401045350-423d6a29a6d4/go.mod h1:hQ5bR5qES5FMITR7zt0ZqKrtpMhlLYBWwYjx2Uud3Lw=
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ=
@@ -288,6 +301,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+2
View File
@@ -23,6 +23,7 @@ const (
SNP PlatformType = iota
VTPM
SNPvTPM
AzureToken
Azure
NoCC
)
@@ -67,6 +68,7 @@ type Provider interface {
VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error
VerifTeeAttestation(report []byte, teeNonce []byte) error
VerifVTpmAttestation(report []byte, vTpmNonce []byte) error
AzureAttestationToken(tokenNonce []byte) ([]byte, error)
}
func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config) error {
+42
View File
@@ -0,0 +1,42 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package azure
import (
"github.com/edgelesssys/go-azguestattestation/maa"
)
type EnvConfig struct {
OSBuild string
OSType string
OSDistro string
MaaURL string
}
func NewEnvConfigFromAgent(agentOSBuild, agentOSType, agentOSDistro, maaURL string) *EnvConfig {
return &EnvConfig{
OSBuild: agentOSBuild,
OSType: agentOSType,
OSDistro: agentOSDistro,
MaaURL: maaURL,
}
}
func InitializeDefaultMAAVars(config *EnvConfig) {
maa.OSBuild = config.OSBuild
maa.OSType = config.OSType
maa.OSDistro = config.OSDistro
}
func (c *EnvConfig) InitializeOSVars(build, osType, osDistro string) {
if build != "" {
c.OSBuild = build
}
if osType != "" {
c.OSType = osType
}
if osDistro != "" {
c.OSDistro = osDistro
}
}
+58
View File
@@ -0,0 +1,58 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package azure
import (
"testing"
"github.com/edgelesssys/go-azguestattestation/maa"
"github.com/stretchr/testify/assert"
)
func TestNewEnvConfigFromAgent(t *testing.T) {
// Given
expectedBuild := "CustomBuild123"
expectedType := "Linux"
expectedDistro := "UVC-Debian"
expectedURL := "https://test.attest.azure.net"
// When
cfg := NewEnvConfigFromAgent(expectedBuild, expectedType, expectedDistro, expectedURL)
// Then
if cfg.OSBuild != expectedBuild {
t.Errorf("expected OSBuild = %s, got %s", expectedBuild, cfg.OSBuild)
}
if cfg.OSType != expectedType {
t.Errorf("expected OSType = %s, got %s", expectedType, cfg.OSType)
}
if cfg.OSDistro != expectedDistro {
t.Errorf("expected OSDistro = %s, got %s", expectedDistro, cfg.OSDistro)
}
if cfg.MaaURL != expectedURL {
t.Errorf("expected MaaURL = %s, got %s", expectedURL, cfg.MaaURL)
}
}
func TestInitializeDefaultMAAVars(t *testing.T) {
cfg := &EnvConfig{
OSBuild: "build123",
OSType: "CustomOS",
OSDistro: "DistroX",
}
InitializeDefaultMAAVars(cfg)
assert.Equal(t, "build123", maa.OSBuild)
assert.Equal(t, "CustomOS", maa.OSType)
assert.Equal(t, "DistroX", maa.OSDistro)
}
func TestInitializeOSVars(t *testing.T) {
cfg := &EnvConfig{}
cfg.InitializeOSVars("buildX", "TypeY", "DistroZ")
assert.Equal(t, "buildX", cfg.OSBuild)
assert.Equal(t, "TypeY", cfg.OSType)
assert.Equal(t, "DistroZ", cfg.OSDistro)
}
+9
View File
@@ -116,6 +116,15 @@ func (a provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []
return nil
}
func (a provider) AzureAttestationToken(tokenNonce []byte) ([]byte, error) {
quote, err := vtpm.FetchAzureAttestation(tokenNonce)
if err != nil {
return nil, errors.Wrap(vtpm.ErrFetchAzureToken, err)
}
return quote, nil
}
func GenerateAttestationPolicy(token string, product string, policy uint64, nonce []byte) (*attestation.Config, error) {
claims, err := validateToken(token)
if err != nil {
+4
View File
@@ -21,6 +21,10 @@ func (e *EmptyProvider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
return cocosai.EmbeddedAttestation, nil
}
func (e *EmptyProvider) AzureAttestationToken(nonce []byte) ([]byte, error) {
return cocosai.EmbeddedAttestation, nil
}
func (e *EmptyProvider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
return nil
}
+58
View File
@@ -79,6 +79,64 @@ func (_c *Provider_Attestation_Call) RunAndReturn(run func([]byte, []byte) ([]by
return _c
}
// AzureAttestationToken provides a mock function with given fields: tokenNonce
func (_m *Provider) AzureAttestationToken(tokenNonce []byte) ([]byte, error) {
ret := _m.Called(tokenNonce)
if len(ret) == 0 {
panic("no return value specified for AzureAttestationToken")
}
var r0 []byte
var r1 error
if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
return rf(tokenNonce)
}
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
r0 = rf(tokenNonce)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(tokenNonce)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Provider_AzureAttestationToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AzureAttestationToken'
type Provider_AzureAttestationToken_Call struct {
*mock.Call
}
// AzureAttestationToken is a helper method to define mock.On call
// - tokenNonce []byte
func (_e *Provider_Expecter) AzureAttestationToken(tokenNonce interface{}) *Provider_AzureAttestationToken_Call {
return &Provider_AzureAttestationToken_Call{Call: _e.mock.On("AzureAttestationToken", tokenNonce)}
}
func (_c *Provider_AzureAttestationToken_Call) Run(run func(tokenNonce []byte)) *Provider_AzureAttestationToken_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]byte))
})
return _c
}
func (_c *Provider_AzureAttestationToken_Call) Return(_a0 []byte, _a1 error) *Provider_AzureAttestationToken_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *Provider_AzureAttestationToken_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Provider_AzureAttestationToken_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)
+24 -3
View File
@@ -5,16 +5,19 @@ package vtpm
import (
"bytes"
"context"
"crypto"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
"strconv"
"github.com/absmach/magistrala/pkg/errors"
"github.com/edgelesssys/go-azguestattestation/maa"
"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/proto/sevsnp"
"github.com/google/go-tpm-tools/client"
@@ -42,9 +45,10 @@ const (
)
var (
ExternalTPM io.ReadWriteCloser
ErrNoHashAlgo = errors.New("hash algo is not supported")
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
ExternalTPM io.ReadWriteCloser
ErrNoHashAlgo = errors.New("hash algo is not supported")
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
ErrFetchAzureToken = errors.New("failed to fetch Azure token")
)
type tpm struct {
@@ -142,6 +146,15 @@ func (v provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []
return VTPMVerify(report, v.pubKey, teeNonce, vTpmNonce, v.writer)
}
func (v provider) AzureAttestationToken(tokenNonce []byte) ([]byte, error) {
quote, err := FetchAzureAttestation(tokenNonce)
if err != nil {
return nil, errors.Wrap(ErrFetchQuote, err)
}
return quote, nil
}
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([]byte, error) {
attestation, err := FetchQuote(vTPMNonce)
if err != nil {
@@ -158,6 +171,14 @@ func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([
return marshalQuote(attestation)
}
func FetchAzureAttestation(tokenNonce []byte) ([]byte, error) {
token, err := maa.Attest(context.Background(), tokenNonce, os.Getenv("AgentMaaURL"), http.DefaultClient)
if err != nil {
return nil, fmt.Errorf("error fetching azure token: %w", err)
}
return []byte(token), nil
}
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte, writer io.Writer) error {
if err := VerifyQuote(quote, pubKeyTLS, vtpmNonce, writer); err != nil {
return fmt.Errorf("failed to verify vTPM quote: %v", err)
+20
View File
@@ -28,6 +28,7 @@ type SDK interface {
Result(ctx context.Context, privKey any, resultFile *os.File) error
Attestation(ctx context.Context, reportData [size64]byte, nonce [size32]byte, attType int, attestationFile *os.File) error
IMAMeasurements(ctx context.Context, resultFile *os.File) ([]byte, error)
AttestationResult(ctx context.Context, nonce [size32]byte, attType int, attestationFile *os.File) error
}
const (
@@ -156,6 +157,25 @@ func (sdk *agentSDK) Attestation(ctx context.Context, reportData [size64]byte, n
return pb.ReceiveAttestation(attestationProgressDescription, fileSize, stream, attestationFile)
}
func (sdk *agentSDK) AttestationResult(ctx context.Context, nonce [size32]byte, attType int, attestationResultFile *os.File) error {
request := &agent.AttestationResultRequest{
TokenNonce: nonce[:],
Type: int32(attType),
}
result, err := sdk.client.AttestationResult(ctx, request)
if err != nil {
return errors.Wrap(errors.New("failed to fetch attestation token"), err)
}
_, err = attestationResultFile.Write(result.GetFile())
if err != nil {
return errors.Wrap(errors.New("failed to write attestation result to file"), err)
}
return nil
}
func signData(userID string, privKey crypto.Signer) ([]byte, error) {
var signature []byte
var err error
+83
View File
@@ -475,6 +475,89 @@ func TestAttestation(t *testing.T) {
}
}
func TestAttestationResult(t *testing.T) {
reportData := make([]byte, 64)
nonce := make([]byte, 64)
report := []byte{
0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
}
conn, err := grpc.NewClient("passthrough://bufnet", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(bufDialer))
if err != nil {
t.Fatalf("Failed to dial bufnet: %v", err)
}
defer conn.Close()
client := agent.NewAgentServiceClient(conn)
sdk := sdk.NewAgentSDK(client)
_, err = rand.Read(reportData)
require.NoError(t, err)
cases := []struct {
name string
nonce [vtpm.Nonce]byte
response *agent.AttestationResultResponse
svcRes []byte
err error
}{
{
name: "fetch attestation report successfully",
nonce: [vtpm.Nonce]byte(nonce),
response: &agent.AttestationResultResponse{
File: report,
},
svcRes: report,
err: nil,
},
{
name: "failed to fetch attestation report",
nonce: [vtpm.Nonce]byte(nonce),
response: &agent.AttestationResultResponse{
File: []byte{},
},
err: nil,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
svcCall := svc.On("AttestationResult", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.svcRes, tc.err)
file, err := os.CreateTemp("", "attestation")
require.NoError(t, err)
t.Cleanup(func() {
os.Remove(file.Name())
})
err = sdk.AttestationResult(context.Background(), tc.nonce, 0, file)
require.NoError(t, file.Close())
st, ok := status.FromError(err)
if !ok {
t.Fatalf("Expected gRPC status error, but got: %v", err)
}
if tc.err != nil {
if st.Message() != tc.err.Error() {
t.Errorf("%s: Expected error message %q, but got %q", tc.name, tc.err.Error(), st.Message())
}
}
res, err := os.ReadFile(file.Name())
require.NoError(t, err)
assert.Equal(t, tc.response.File, res, tc.name)
svcCall.Unset()
})
}
}
func generateKeys(t *testing.T, keyType string) (priv any, pub []byte) {
switch keyType {
case "ecdsa":
+49
View File
@@ -124,6 +124,55 @@ func (_c *SDK_Attestation_Call) RunAndReturn(run func(context.Context, [64]byte,
return _c
}
// AttestationResult provides a mock function with given fields: ctx, nonce, attType, attestationFile
func (_m *SDK) AttestationResult(ctx context.Context, nonce [32]byte, attType int, attestationFile *os.File) error {
ret := _m.Called(ctx, nonce, attType, attestationFile)
if len(ret) == 0 {
panic("no return value specified for AttestationResult")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, [32]byte, int, *os.File) error); ok {
r0 = rf(ctx, nonce, attType, attestationFile)
} else {
r0 = ret.Error(0)
}
return r0
}
// SDK_AttestationResult_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AttestationResult'
type SDK_AttestationResult_Call struct {
*mock.Call
}
// AttestationResult is a helper method to define mock.On call
// - ctx context.Context
// - nonce [32]byte
// - attType int
// - attestationFile *os.File
func (_e *SDK_Expecter) AttestationResult(ctx interface{}, nonce interface{}, attType interface{}, attestationFile interface{}) *SDK_AttestationResult_Call {
return &SDK_AttestationResult_Call{Call: _e.mock.On("AttestationResult", ctx, nonce, attType, attestationFile)}
}
func (_c *SDK_AttestationResult_Call) Run(run func(ctx context.Context, nonce [32]byte, attType int, attestationFile *os.File)) *SDK_AttestationResult_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].([32]byte), args[2].(int), args[3].(*os.File))
})
return _c
}
func (_c *SDK_AttestationResult_Call) Return(_a0 error) *SDK_AttestationResult_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *SDK_AttestationResult_Call) RunAndReturn(run func(context.Context, [32]byte, int, *os.File) error) *SDK_AttestationResult_Call {
_c.Call.Return(run)
return _c
}
// Data provides a mock function with given fields: ctx, dataset, filename, privKey
func (_m *SDK) Data(ctx context.Context, dataset *os.File, filename string, privKey interface{}) error {
ret := _m.Called(ctx, dataset, filename, privKey)