mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
COCOS-395 - Cloud Provider Firmware Integration (#415)
* add CC platform identification capability * add token verification * add snp azure * add azure snp report verification * fix linter errors * fix agent tests * expand the CC provider * fix azure atls * rebase branch * add nonce check for azure token * rename package attestations * remove alias attestations --------- Co-authored-by: Ubuntu <azureuser@UVCTestCVM.bu0p0zdolasezg1jifpyqhaxuc.dx.internal.cloudapp.net>
This commit is contained in:
committed by
GitHub
parent
5c60bc2a48
commit
3102114ff3
+49
-55
@@ -5,14 +5,15 @@ package atls
|
||||
|
||||
// #cgo LDFLAGS: -lssl -lcrypto
|
||||
// #include "extensions.h"
|
||||
// #include <string.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"crypto/sha3"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime/cgo"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
@@ -20,15 +21,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/azure"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||
)
|
||||
|
||||
const (
|
||||
NoTee int = iota
|
||||
AmdSevSnp
|
||||
)
|
||||
|
||||
const (
|
||||
noError = 0
|
||||
errorZeroReturn = 6
|
||||
@@ -37,6 +35,7 @@ const (
|
||||
errorSyscall = 5
|
||||
errorSsl = 1
|
||||
waitTime = 2
|
||||
vmpl2 = 2
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -51,57 +50,42 @@ var (
|
||||
errConnCreate = errors.New("could not create connection")
|
||||
)
|
||||
|
||||
type ValidationVerification func(data1, data2, data3, data4 []byte) error
|
||||
type FetchAttestation func(data1, data2, data3 []byte) ([]byte, error)
|
||||
|
||||
func registerFetchAttestation(callback FetchAttestation) uintptr {
|
||||
handle := cgo.NewHandle(callback)
|
||||
return uintptr(handle)
|
||||
func formTeeData(pubKey []byte, teeNonce []byte) []byte {
|
||||
combined := append(pubKey, teeNonce...)
|
||||
sum := sha3.Sum512(combined)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
func registerValidationVerification(callback ValidationVerification) uintptr {
|
||||
handle := cgo.NewHandle(callback)
|
||||
return uintptr(handle)
|
||||
}
|
||||
|
||||
//export validationVerificationCallback
|
||||
func validationVerificationCallback(teeType C.int) uintptr {
|
||||
switch int(teeType) {
|
||||
case NoTee:
|
||||
return uintptr(0)
|
||||
case AmdSevSnp:
|
||||
return registerValidationVerification(vtpm.VTPMVerify)
|
||||
func getPlatformProvider(platformType attestation.PlatformType, pubKey []byte) (attestation.Provider, error) {
|
||||
switch platformType {
|
||||
case attestation.SNPvTPM:
|
||||
return vtpm.New(pubKey, true, vmpl2, nil), nil
|
||||
case attestation.Azure:
|
||||
return azure.New(nil), nil
|
||||
default:
|
||||
return uintptr(0)
|
||||
}
|
||||
}
|
||||
|
||||
//export fetchAttestationCallback
|
||||
func fetchAttestationCallback(teeType C.int) uintptr {
|
||||
switch int(teeType) {
|
||||
case NoTee:
|
||||
return uintptr(0)
|
||||
case AmdSevSnp:
|
||||
return registerFetchAttestation(vtpm.FetchATLSQuote)
|
||||
default:
|
||||
return uintptr(0)
|
||||
return nil, fmt.Errorf("unsupported platform type: %d", platformType)
|
||||
}
|
||||
}
|
||||
|
||||
//export callVerificationValidationCallback
|
||||
func callVerificationValidationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKeyLen C.int, quote *C.uchar, quoteSize C.int, teeNonce *C.uchar, nonce *C.uchar) C.int {
|
||||
handle := cgo.Handle(callbackHandle)
|
||||
defer handle.Delete()
|
||||
|
||||
callback := handle.Value().(ValidationVerification)
|
||||
func callVerificationValidationCallback(platformType C.int, pubKey *C.uchar, pubKeyLen C.int, attestReport *C.uchar, attestReportSize C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar) C.int {
|
||||
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
||||
attestationReport := C.GoBytes(unsafe.Pointer(quote), quoteSize)
|
||||
teeData := C.GoBytes(unsafe.Pointer(teeNonce), quoteprovider.Nonce)
|
||||
nonceData := C.GoBytes(unsafe.Pointer(nonce), vtpm.Nonce)
|
||||
teeNonceData := C.GoBytes(unsafe.Pointer(teeNonceByte), quoteprovider.Nonce)
|
||||
vTPMNonce := C.GoBytes(unsafe.Pointer(vTPMNonceByte), vtpm.Nonce)
|
||||
pType := attestation.PlatformType(int(platformType))
|
||||
attestationReport := C.GoBytes(unsafe.Pointer(attestReport), attestReportSize)
|
||||
|
||||
teeData := formTeeData(pubKeyCert, teeNonceData)
|
||||
|
||||
err := callback(attestationReport, pubKeyCert, teeData, nonceData)
|
||||
provider, err := getPlatformProvider(pType, pubKeyCert)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "callback failed %v", err)
|
||||
fmt.Fprintf(os.Stderr, "no attestation provider found for platform type %s", err.Error())
|
||||
return C.int(-1)
|
||||
}
|
||||
|
||||
err = provider.VerifyAttestation(attestationReport, teeData, vTPMNonce)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "verification callback failed %s", err.Error())
|
||||
return C.int(-1)
|
||||
}
|
||||
|
||||
@@ -109,18 +93,23 @@ func callVerificationValidationCallback(callbackHandle uintptr, pubKey *C.uchar,
|
||||
}
|
||||
|
||||
//export callFetchAttestationCallback
|
||||
func callFetchAttestationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKeyLen C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar, outlen *C.ulong) *C.uchar {
|
||||
handle := cgo.Handle(callbackHandle)
|
||||
defer handle.Delete()
|
||||
|
||||
callback := handle.Value().(FetchAttestation)
|
||||
func callFetchAttestationCallback(platformType C.int, pubKey *C.uchar, pubKeyLen C.int, teeNonceByte *C.uchar, vTPMNonceByte *C.uchar, outlen *C.ulong) *C.uchar {
|
||||
pubKeyCert := C.GoBytes(unsafe.Pointer(pubKey), pubKeyLen)
|
||||
teeNonceData := C.GoBytes(unsafe.Pointer(teeNonceByte), quoteprovider.Nonce)
|
||||
vTPMNonce := C.GoBytes(unsafe.Pointer(vTPMNonceByte), vtpm.Nonce)
|
||||
pType := attestation.PlatformType(int(platformType))
|
||||
|
||||
quote, err := callback(pubKeyCert, teeNonceData, vTPMNonce)
|
||||
teeData := formTeeData(pubKeyCert, teeNonceData)
|
||||
|
||||
provider, err := getPlatformProvider(pType, pubKeyCert)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "attestation callback returned nil")
|
||||
fmt.Fprintf(os.Stderr, "no attestation provider found for platform type %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
quote, err := provider.Attestation(teeData, vTPMNonce)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "attestation callback returned nil: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -136,6 +125,11 @@ func callFetchAttestationCallback(callbackHandle uintptr, pubKey *C.uchar, pubKe
|
||||
return (*C.uchar)(resultC)
|
||||
}
|
||||
|
||||
//export returnCCPlatformType
|
||||
func returnCCPlatformType() int32 {
|
||||
return int32(attestation.CCPlatform())
|
||||
}
|
||||
|
||||
type ATLSServerListener struct {
|
||||
tlsListener *C.tls_server_connection
|
||||
}
|
||||
@@ -252,7 +246,7 @@ func (c *ATLSConn) Read(b []byte) (int, error) {
|
||||
return 0, syscall.ECONNRESET // return connection reset error.
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "SSL error occurred: %d\n", errCode)
|
||||
return 0, fmt.Errorf("SSL error\n")
|
||||
return 0, fmt.Errorf("SSL error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-53
@@ -7,41 +7,28 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern int callVerificationValidationCallback(uintptr_t callbackHandle, const u_char* pubKey, int pubKeyLen, const u_char* quote, int quoteSize, const u_char* teeNonce, const u_char* nonce);
|
||||
extern u_char* callFetchAttestationCallback(uintptr_t callbackHandle, const u_char* pubKey, int pubKeyLen, const u_char* teeNonceByte, const u_char* vTPMNonceByte, unsigned long* outlen);
|
||||
extern int callVerificationValidationCallback(int platformType, const u_char* pubKey, int pubKeyLen, const u_char* quote, int quoteSize, const u_char* teeNonceByte, const u_char* vTPMNonceByte);
|
||||
extern u_char* callFetchAttestationCallback(int platformType, const u_char* pubKey, int pubKeyLen, const u_char* teeNonceByte, const u_char* vTPMNonceByte, unsigned long* outlen);
|
||||
extern uintptr_t validationVerificationCallback(int teeType);
|
||||
extern uintptr_t fetchAttestationCallback(int teeType);
|
||||
extern uintptr_t getPlatformTypeHandle(int platformType, u_char *teeNonce, u_char *vtpmNonce);
|
||||
extern int returnCCPlatformType();
|
||||
|
||||
int triggerVerificationValidationCallback(uintptr_t callbackHandle, u_char* pub_key, int pub_key_len, u_char *quote, int quote_size, u_char *tee_nonce, u_char *vtpm_nonce) {
|
||||
int triggerVerificationValidationCallback(int platformType, u_char* pub_key, int pub_key_len, u_char *quote, int quote_size, u_char *tee_nonce, u_char *vtpm_nonce) {
|
||||
if (quote == NULL || vtpm_nonce == NULL || tee_nonce == NULL || pub_key == NULL) {
|
||||
fprintf(stderr, "attestation and noce and public key cannot be NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return callVerificationValidationCallback(callbackHandle, pub_key, pub_key_len, quote, quote_size, tee_nonce, vtpm_nonce);
|
||||
return callVerificationValidationCallback(platformType, pub_key, pub_key_len, quote, quote_size, tee_nonce, vtpm_nonce);
|
||||
}
|
||||
|
||||
u_char* triggerFetchAttestationCallback(uintptr_t callback_handle, u_char* pub_key, int pub_key_len, char *tee_nonce, char *vtpm_nonce, unsigned long *outlen) {
|
||||
u_char* triggerFetchAttestationCallback(int platformType, u_char* pub_key, int pub_key_len, char *tee_nonce, char *vtpm_nonce, unsigned long *outlen) {
|
||||
if(tee_nonce == NULL || vtpm_nonce == NULL) {
|
||||
fprintf(stderr, "Report data cannot be NULL");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return callFetchAttestationCallback(callback_handle, pub_key, pub_key_len, tee_nonce, vtpm_nonce, outlen);
|
||||
}
|
||||
|
||||
int check_sev_snp() {
|
||||
int fd = open(SEV_GUEST_DRIVER_PATH, O_RDONLY);
|
||||
|
||||
if (fd == -1) {
|
||||
perror("Error opening /dev/sev-guest");
|
||||
fprintf(stderr, "SEV guest driver is not available.\n");
|
||||
return -1;
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return callFetchAttestationCallback(platformType, pub_key, pub_key_len, tee_nonce, vtpm_nonce, outlen);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -78,9 +65,9 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
||||
}
|
||||
|
||||
if (ext_data != NULL) {
|
||||
if (RAND_bytes(ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE) != 1) {
|
||||
if (RAND_bytes(ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE) != 1) {
|
||||
perror("could not generate random bytes for vtpm nonce, will use SSL client random");
|
||||
SSL_get_client_random(s, ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE);
|
||||
SSL_get_client_random(s, ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||
}
|
||||
|
||||
if (RAND_bytes(ext_data->er.tee_nonce, REPORT_DATA_SIZE) != 1) {
|
||||
@@ -94,10 +81,8 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(er->vtpm_nonce, ext_data->er.vtpm_nonce, CLIENT_RANDOM_SIZE);
|
||||
memcpy(er->vtpm_nonce, ext_data->er.vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||
memcpy(er->tee_nonce, ext_data->er.tee_nonce, REPORT_DATA_SIZE);
|
||||
er->tee_type = AMD_TEE;
|
||||
ext_data->er.tee_type = AMD_TEE;
|
||||
|
||||
*out = (const u_char *)er;
|
||||
*outlen = sizeof(evidence_request);
|
||||
@@ -116,19 +101,8 @@ int evidence_request_ext_add_cb(SSL *s, unsigned int ext_type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (check_sev_snp() > 0) {
|
||||
*platform_type = AMD_TEE;
|
||||
} else {
|
||||
*platform_type = NO_TEE;
|
||||
}
|
||||
|
||||
if ((*platform_type != ext_data->er.tee_type) || (*platform_type == NO_TEE)) {
|
||||
*platform_type = NO_TEE;
|
||||
ext_data->er.tee_type = NO_TEE;
|
||||
} else {
|
||||
ext_data->er.tee_type = AMD_TEE;
|
||||
ext_data->fetch_attestation_handler = fetchAttestationCallback(ext_data->er.tee_type);
|
||||
}
|
||||
*platform_type = returnCCPlatformType();
|
||||
ext_data->platform_type = *platform_type;
|
||||
|
||||
*out = (u_char*)platform_type;
|
||||
*outlen = sizeof(int32_t);
|
||||
@@ -164,9 +138,8 @@ int evidence_request_ext_parse_cb(SSL *s, unsigned int ext_type,
|
||||
evidence_request *er = (evidence_request*)in;
|
||||
|
||||
if (ext_data != NULL) {
|
||||
memcpy(ext_data->er.vtpm_nonce, er->vtpm_nonce, CLIENT_RANDOM_SIZE);
|
||||
memcpy(ext_data->er.vtpm_nonce, er->vtpm_nonce, NONCE_RANDOM_SIZE);
|
||||
memcpy(ext_data->er.tee_nonce, er->tee_nonce, REPORT_DATA_SIZE);
|
||||
ext_data->er.tee_type = er->tee_type;
|
||||
} else {
|
||||
fprintf(stderr, "parse_arg is NULL\n");
|
||||
return 0;
|
||||
@@ -175,18 +148,11 @@ int evidence_request_ext_parse_cb(SSL *s, unsigned int ext_type,
|
||||
}
|
||||
case SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS:
|
||||
{
|
||||
int *tee_type = (int*)in;
|
||||
int *platform_type = (int*)in;
|
||||
tls_extension_data *ext_data = (tls_extension_data*)parse_arg;
|
||||
|
||||
if (ext_data != NULL) {
|
||||
ext_data->er.tee_type = *tee_type;
|
||||
|
||||
if (ext_data->er.tee_type != NO_TEE) {
|
||||
ext_data->verification_validation_handler = validationVerificationCallback(ext_data->er.tee_type);
|
||||
} else {
|
||||
fprintf(stderr, "must use a TEE for aTLS\n");
|
||||
return 0;
|
||||
}
|
||||
ext_data->platform_type = *platform_type;
|
||||
} else {
|
||||
fprintf(stderr, "parse_arg is NULL\n");
|
||||
return 0;
|
||||
@@ -253,7 +219,7 @@ int attestation_certificate_ext_add_cb(SSL *s, unsigned int ext_type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
quote = triggerFetchAttestationCallback(ext_data->fetch_attestation_handler, pubkey_buf, pubkey_len, ext_data->er.tee_nonce, ext_data->er.vtpm_nonce, &len);
|
||||
quote = triggerFetchAttestationCallback(ext_data->platform_type, pubkey_buf, pubkey_len, ext_data->er.tee_nonce, ext_data->er.vtpm_nonce, &len);
|
||||
if (quote == NULL) {
|
||||
fprintf(stderr, "attestation report is NULL\n");
|
||||
*al = SSL_AD_INTERNAL_ERROR;
|
||||
@@ -291,7 +257,6 @@ int attestation_certificate_ext_parse_cb(SSL *s, unsigned int ext_type,
|
||||
switch (context)
|
||||
{
|
||||
case SSL_EXT_CLIENT_HELLO:
|
||||
// Return 1 so the server can return the custom certificate extension.
|
||||
return 1;
|
||||
case SSL_EXT_TLS1_3_CERTIFICATE:
|
||||
{
|
||||
@@ -324,7 +289,7 @@ int attestation_certificate_ext_parse_cb(SSL *s, unsigned int ext_type,
|
||||
}
|
||||
memcpy(quote, in, inlen);
|
||||
|
||||
res = triggerVerificationValidationCallback(ext_data->verification_validation_handler,
|
||||
res = triggerVerificationValidationCallback(ext_data->platform_type,
|
||||
pubkey_buf,
|
||||
pubkey_len,
|
||||
quote,
|
||||
|
||||
+3
-11
@@ -7,25 +7,19 @@
|
||||
#define EVIDENCE_REQUEST_HELLO_EXTENSION_TYPE 65
|
||||
#define ATTESTATION_CERTIFICATE_EXTENSION_TYPE 66
|
||||
#define REPORT_DATA_SIZE 64
|
||||
#define CLIENT_RANDOM_SIZE 32
|
||||
#define NONCE_RANDOM_SIZE 32
|
||||
#define TLS_CLIENT_CTX 0
|
||||
#define TLS_SERVER_CTX 1
|
||||
|
||||
#define SEV_GUEST_DRIVER_PATH "/dev/sev-guest"
|
||||
#define NO_TEE 0
|
||||
#define AMD_TEE 1
|
||||
|
||||
typedef struct evidence_request
|
||||
{
|
||||
int tee_type;
|
||||
char vtpm_nonce[CLIENT_RANDOM_SIZE];
|
||||
char vtpm_nonce[NONCE_RANDOM_SIZE];
|
||||
char tee_nonce[REPORT_DATA_SIZE];
|
||||
} evidence_request;
|
||||
|
||||
typedef struct tls_extension_data
|
||||
{
|
||||
uintptr_t fetch_attestation_handler;
|
||||
uintptr_t verification_validation_handler;
|
||||
int platform_type;
|
||||
evidence_request er;
|
||||
} tls_extension_data;
|
||||
|
||||
@@ -37,7 +31,6 @@ typedef struct tls_server_connection
|
||||
char* key;
|
||||
int key_len;
|
||||
struct sockaddr_storage addr;
|
||||
uintptr_t fetch_attestation_handler;
|
||||
} tls_server_connection;
|
||||
|
||||
typedef struct tls_connection
|
||||
@@ -61,7 +54,6 @@ int set_socket_read_timeout(tls_connection* conn, int timeout_sec, int timeout_u
|
||||
int set_socket_write_timeout(tls_connection* conn, int timeout_sec, int timeout_usec);
|
||||
char* tls_return_addr(struct sockaddr_storage *addr);
|
||||
int tls_return_port(struct sockaddr_storage *addr);
|
||||
int compute_sha256_of_public_key(X509 *cert, unsigned char *hash);
|
||||
|
||||
// Extensions
|
||||
void evidence_request_ext_free_cb(SSL *s, unsigned int ext_type,
|
||||
|
||||
+1
-2
@@ -289,9 +289,8 @@ tls_connection* tls_server_accept(tls_server_connection *tls_server) {
|
||||
goto cleanup_fd;
|
||||
}
|
||||
|
||||
// Set file descriptor and assign handlers
|
||||
// Set file descriptor
|
||||
conn->socket_fd = client_fd;
|
||||
conn->tls_ext_data.fetch_attestation_handler = tls_server->fetch_attestation_handler;
|
||||
SSL_set_fd(conn->ssl, client_fd);
|
||||
|
||||
// Get local address
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package config
|
||||
package attestation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/google/go-sev-guest/client"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-tpm/legacy/tpm2"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
type AttestationType int32
|
||||
type PlatformType int
|
||||
|
||||
const (
|
||||
SNP AttestationType = iota
|
||||
SNP PlatformType = iota
|
||||
VTPM
|
||||
SNPvTPM
|
||||
Azure
|
||||
NoCC
|
||||
)
|
||||
|
||||
const (
|
||||
azureMetadataUrl = "http://169.254.169.254/metadata/instance"
|
||||
azureApiVersion = "2021-02-01"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -43,6 +55,20 @@ type Config struct {
|
||||
*PcrConfig
|
||||
}
|
||||
|
||||
type ccCheck struct {
|
||||
checkFunc func() bool
|
||||
platform PlatformType
|
||||
}
|
||||
|
||||
type Provider interface {
|
||||
Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error)
|
||||
TeeAttestation(teeNonce []byte) ([]byte, error)
|
||||
VTpmAttestation(vTpmNonce []byte) ([]byte, error)
|
||||
VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error
|
||||
VerifTeeAttestation(report []byte, teeNonce []byte) error
|
||||
VerifVTpmAttestation(report []byte, vTpmNonce []byte) error
|
||||
}
|
||||
|
||||
func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config) error {
|
||||
if policyPath != "" {
|
||||
policyData, err := os.ReadFile(policyPath)
|
||||
@@ -69,3 +95,64 @@ func ReadAttestationPolicyFromByte(policyData []byte, attestationConfiguration *
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CCPlatform returns the type of the confidential computing platform.
|
||||
func CCPlatform() PlatformType {
|
||||
checks := []ccCheck{
|
||||
{SevGuestvTPMExists, SNPvTPM},
|
||||
{SevGuesDeviceExists, SNP},
|
||||
{isAzureVM, Azure},
|
||||
}
|
||||
|
||||
for _, c := range checks {
|
||||
if c.checkFunc() {
|
||||
return c.platform
|
||||
}
|
||||
}
|
||||
return NoCC
|
||||
}
|
||||
|
||||
func SevGuesDeviceExists() bool {
|
||||
d, err := client.OpenDevice()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
d.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func SevGuestvTPMExists() bool {
|
||||
d, err := tpm2.OpenTPM()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
d.Close()
|
||||
|
||||
return SevGuesDeviceExists()
|
||||
}
|
||||
|
||||
func isAzureVM() bool {
|
||||
client := &http.Client{}
|
||||
url := fmt.Sprintf("%s?api-version=%s", azureMetadataUrl, azureApiVersion)
|
||||
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Add("Metadata", "true")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return len(body) > 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package azure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/edgelesssys/go-azguestattestation/maa"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/kds"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
"github.com/google/go-sev-guest/tools/lib/report"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/vtpm"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var MaaURL = "https://sharedeus2.eus2.attest.azure.net"
|
||||
|
||||
var _ attestation.Provider = (*provider)(nil)
|
||||
|
||||
type provider struct {
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
func New(writer io.Writer) attestation.Provider {
|
||||
return provider{writer: writer}
|
||||
}
|
||||
|
||||
func (a provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||
var tokenNonce [vtpm.Nonce]byte
|
||||
copy(tokenNonce[:], teeNonce)
|
||||
|
||||
params, err := maa.NewParameters(context.Background(), tokenNonce[:], http.DefaultClient, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get report: %w", err)
|
||||
}
|
||||
|
||||
snpReport, err := report.ParseAttestation(params.SNPReport, "bin")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse SNP report: %w", err)
|
||||
}
|
||||
|
||||
quote, err := vtpm.FetchQuote(vTpmNonce)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch quote: %w", err)
|
||||
}
|
||||
|
||||
quote.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
||||
SevSnpAttestation: snpReport,
|
||||
}
|
||||
|
||||
return proto.Marshal(quote)
|
||||
}
|
||||
|
||||
func (a provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||
var tokenNonce [vtpm.Nonce]byte
|
||||
copy(tokenNonce[:], teeNonce)
|
||||
|
||||
params, err := maa.NewParameters(context.Background(), tokenNonce[:], http.DefaultClient, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get report: %w", err)
|
||||
}
|
||||
|
||||
return params.SNPReport, nil
|
||||
}
|
||||
|
||||
func (a provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||
quote, err := vtpm.FetchQuote(vTpmNonce)
|
||||
if err != nil {
|
||||
return []byte{}, errors.Wrap(vtpm.ErrFetchQuote, err)
|
||||
}
|
||||
|
||||
return proto.Marshal(quote)
|
||||
}
|
||||
|
||||
func (a provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
attestationReport, err := abi.ReportCertsToProto(report)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||
}
|
||||
|
||||
return quoteprovider.VerifyAttestationReportTLS(attestationReport, teeNonce)
|
||||
}
|
||||
|
||||
func (a provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
return vtpm.VerifyQuote(report, nil, vTpmNonce, a.writer)
|
||||
}
|
||||
|
||||
func (a provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
var tokenNonce [vtpm.Nonce]byte
|
||||
copy(tokenNonce[:], teeNonce)
|
||||
|
||||
quote := &attest.Attestation{}
|
||||
err := proto.Unmarshal(report, quote)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal vTPM quote: %w", err)
|
||||
}
|
||||
|
||||
snpReport := quote.GetSevSnpAttestation()
|
||||
if err = quoteprovider.VerifyAttestationReportTLS(snpReport, nil); err != nil {
|
||||
return fmt.Errorf("failed to verify vTPM attestation report: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenerateAttestationPolicy(token string, product string, policy uint64, nonce []byte) (*attestation.Config, error) {
|
||||
claims, err := validateToken(token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to validate token: %w", err)
|
||||
}
|
||||
|
||||
if err := validateClaims(claims, nonce); err != nil {
|
||||
return nil, fmt.Errorf("failed to validate claims: %w", err)
|
||||
}
|
||||
|
||||
tee, ok := claims["x-ms-isolation-tee"].(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get tee from claims")
|
||||
}
|
||||
|
||||
familyIdString, ok := tee["x-ms-sevsnpvm-familyId"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get familyId from claims")
|
||||
}
|
||||
|
||||
familyId, err := hex.DecodeString(familyIdString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode familyId: %w", err)
|
||||
}
|
||||
|
||||
imageIdString, ok := tee["x-ms-sevsnpvm-imageId"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get imageId from claims")
|
||||
}
|
||||
imageId, err := hex.DecodeString(imageIdString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode imageId: %w", err)
|
||||
}
|
||||
|
||||
measurementString, ok := tee["x-ms-sevsnpvm-launchmeasurement"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get measurement from claims")
|
||||
}
|
||||
measurement, err := hex.DecodeString(measurementString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode measurement: %w", err)
|
||||
}
|
||||
|
||||
bootloaderVersion, ok := tee["x-ms-sevsnpvm-bootloader-svn"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get bootloader version from claims")
|
||||
}
|
||||
|
||||
teeVersion, ok := tee["x-ms-sevsnpvm-tee-svn"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get tee version from claims")
|
||||
}
|
||||
|
||||
snpVersion, ok := tee["x-ms-sevsnpvm-snpfw-svn"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get snp version from claims")
|
||||
}
|
||||
|
||||
microcodeVersion, ok := tee["x-ms-sevsnpvm-microcode-svn"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get microcode version from claims")
|
||||
}
|
||||
|
||||
minimalTCBParts := kds.TCBParts{
|
||||
BlSpl: uint8(bootloaderVersion),
|
||||
TeeSpl: uint8(teeVersion),
|
||||
SnpSpl: uint8(snpVersion),
|
||||
UcodeSpl: uint8(microcodeVersion),
|
||||
}
|
||||
|
||||
minimalTCB, err := kds.ComposeTCBParts(minimalTCBParts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compose TCB parts: %w", err)
|
||||
}
|
||||
|
||||
guestSVN, ok := tee["x-ms-sevsnpvm-guestsvn"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get guest SVN from claims")
|
||||
}
|
||||
|
||||
idKeyDigestString, ok := tee["x-ms-sevsnpvm-idkeydigest"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get idKeyDigest from claims")
|
||||
}
|
||||
idKeyDigest, err := hex.DecodeString(idKeyDigestString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode idKeyDigest: %w", err)
|
||||
}
|
||||
|
||||
reportIDString, ok := tee["x-ms-sevsnpvm-reportid"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to get reportID from claims")
|
||||
}
|
||||
reportID, err := hex.DecodeString(reportIDString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode reportID: %w", err)
|
||||
}
|
||||
|
||||
sevProduct := quoteprovider.GetProductName(product)
|
||||
|
||||
return &attestation.Config{
|
||||
Config: &check.Config{
|
||||
RootOfTrust: &check.RootOfTrust{
|
||||
CheckCrl: true,
|
||||
},
|
||||
Policy: &check.Policy{
|
||||
ImageId: imageId,
|
||||
FamilyId: familyId,
|
||||
Measurement: measurement,
|
||||
MinimumGuestSvn: uint32(guestSVN),
|
||||
MinimumTcb: uint64(minimalTCB),
|
||||
TrustedIdKeyHashes: [][]byte{idKeyDigest},
|
||||
ReportId: reportID,
|
||||
Product: &sevsnp.SevProduct{Name: sevProduct},
|
||||
Policy: policy,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validateToken(token string) (map[string]interface{}, error) {
|
||||
unverifiedToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse token: %w", err)
|
||||
}
|
||||
|
||||
jku, jkuOk := unverifiedToken.Header["jku"].(string)
|
||||
if !jkuOk {
|
||||
return nil, fmt.Errorf("token is missing jku or kid in header")
|
||||
}
|
||||
|
||||
MaaUrlCerts := MaaURL
|
||||
if MaaURL == "" {
|
||||
MaaUrlCerts = jku
|
||||
}
|
||||
|
||||
keySet, err := maa.GetKeySet(context.Background(), MaaUrlCerts, http.DefaultClient)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get key set: %w", err)
|
||||
}
|
||||
|
||||
claims, err := maa.ValidateToken(token, keySet)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to validate token: %w", err)
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
func validateClaims(claims map[string]interface{}, nonce []byte) error {
|
||||
runtime, ok := claims["x-ms-runtime"].(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to get runtime from claims")
|
||||
}
|
||||
|
||||
payload, ok := runtime["client-payload"].(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to get client payload from claims")
|
||||
}
|
||||
|
||||
tokenNonce, ok := payload["nonce"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to get nonce from claims")
|
||||
}
|
||||
|
||||
if tokenNonce != base64.StdEncoding.EncodeToString(nonce) {
|
||||
return fmt.Errorf("nonce mismatch: expected %s, got %s", base64.StdEncoding.EncodeToString(nonce), tokenNonce)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package attestation
|
||||
|
||||
import cocosai "github.com/ultravioletrs/cocos"
|
||||
|
||||
var _ Provider = (*EmptyProvider)(nil)
|
||||
|
||||
type EmptyProvider struct{}
|
||||
|
||||
func (e *EmptyProvider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||
return cocosai.EmbeddedAttestation, nil
|
||||
}
|
||||
|
||||
func (e *EmptyProvider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||
return cocosai.EmbeddedAttestation, nil
|
||||
}
|
||||
|
||||
func (e *EmptyProvider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||
return cocosai.EmbeddedAttestation, nil
|
||||
}
|
||||
|
||||
func (e *EmptyProvider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *EmptyProvider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *EmptyProvider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
return nil
|
||||
}
|
||||
@@ -9,12 +9,12 @@ import (
|
||||
"io"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/google/gce-tcb-verifier/proto/endorsement"
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
"github.com/google/go-sev-guest/tools/lib/report"
|
||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -77,8 +77,8 @@ func GetLaunchEndorsement(ctx context.Context, measurement384 string) (*endorsem
|
||||
return &goldenUEFI, nil
|
||||
}
|
||||
|
||||
func GenerateAttestationPolicy(endorsement *endorsement.VMGoldenMeasurement, vcpuNum uint32) (*config.Config, error) {
|
||||
attestationPolicy := config.Config{PcrConfig: &config.PcrConfig{}, Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}}
|
||||
func GenerateAttestationPolicy(endorsement *endorsement.VMGoldenMeasurement, vcpuNum uint32) (*attestation.Config, error) {
|
||||
attestationPolicy := attestation.Config{PcrConfig: &attestation.PcrConfig{}, Config: &check.Config{RootOfTrust: &check.RootOfTrust{}, Policy: &check.Policy{}}}
|
||||
attestationPolicy.Config.Policy.Policy = endorsement.SevSnp.Policy
|
||||
attestationPolicy.Config.Policy.Measurement = endorsement.SevSnp.Measurements[vcpuNum]
|
||||
attestationPolicy.Config.RootOfTrust.DisallowNetwork = false
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by mockery v2.53.3. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
// Provider is an autogenerated mock type for the Provider type
|
||||
type Provider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type Provider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *Provider) EXPECT() *Provider_Expecter {
|
||||
return &Provider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Attestation provides a mock function with given fields: teeNonce, vTpmNonce
|
||||
func (_m *Provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||
ret := _m.Called(teeNonce, vTpmNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Attestation")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([]byte, []byte) ([]byte, error)); ok {
|
||||
return rf(teeNonce, vTpmNonce)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([]byte, []byte) []byte); ok {
|
||||
r0 = rf(teeNonce, vTpmNonce)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([]byte, []byte) error); ok {
|
||||
r1 = rf(teeNonce, vTpmNonce)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Provider_Attestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Attestation'
|
||||
type Provider_Attestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Attestation is a helper method to define mock.On call
|
||||
// - teeNonce []byte
|
||||
// - vTpmNonce []byte
|
||||
func (_e *Provider_Expecter) Attestation(teeNonce interface{}, vTpmNonce interface{}) *Provider_Attestation_Call {
|
||||
return &Provider_Attestation_Call{Call: _e.mock.On("Attestation", teeNonce, vTpmNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_Attestation_Call) Run(run func(teeNonce []byte, vTpmNonce []byte)) *Provider_Attestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte), args[1].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Attestation_Call) Return(_a0 []byte, _a1 error) *Provider_Attestation_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_Attestation_Call) RunAndReturn(run func([]byte, []byte) ([]byte, error)) *Provider_Attestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// TeeAttestation provides a mock function with given fields: teeNonce
|
||||
func (_m *Provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||
ret := _m.Called(teeNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for TeeAttestation")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
|
||||
return rf(teeNonce)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
|
||||
r0 = rf(teeNonce)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([]byte) error); ok {
|
||||
r1 = rf(teeNonce)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Provider_TeeAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TeeAttestation'
|
||||
type Provider_TeeAttestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// TeeAttestation is a helper method to define mock.On call
|
||||
// - teeNonce []byte
|
||||
func (_e *Provider_Expecter) TeeAttestation(teeNonce interface{}) *Provider_TeeAttestation_Call {
|
||||
return &Provider_TeeAttestation_Call{Call: _e.mock.On("TeeAttestation", teeNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_TeeAttestation_Call) Run(run func(teeNonce []byte)) *Provider_TeeAttestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_TeeAttestation_Call) Return(_a0 []byte, _a1 error) *Provider_TeeAttestation_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_TeeAttestation_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Provider_TeeAttestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// VTpmAttestation provides a mock function with given fields: vTpmNonce
|
||||
func (_m *Provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||
ret := _m.Called(vTpmNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for VTpmAttestation")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
|
||||
return rf(vTpmNonce)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
|
||||
r0 = rf(vTpmNonce)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([]byte) error); ok {
|
||||
r1 = rf(vTpmNonce)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Provider_VTpmAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VTpmAttestation'
|
||||
type Provider_VTpmAttestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// VTpmAttestation is a helper method to define mock.On call
|
||||
// - vTpmNonce []byte
|
||||
func (_e *Provider_Expecter) VTpmAttestation(vTpmNonce interface{}) *Provider_VTpmAttestation_Call {
|
||||
return &Provider_VTpmAttestation_Call{Call: _e.mock.On("VTpmAttestation", vTpmNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_VTpmAttestation_Call) Run(run func(vTpmNonce []byte)) *Provider_VTpmAttestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VTpmAttestation_Call) Return(_a0 []byte, _a1 error) *Provider_VTpmAttestation_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VTpmAttestation_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Provider_VTpmAttestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// VerifTeeAttestation provides a mock function with given fields: report, teeNonce
|
||||
func (_m *Provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
ret := _m.Called(report, teeNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for VerifTeeAttestation")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
|
||||
r0 = rf(report, teeNonce)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_VerifTeeAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifTeeAttestation'
|
||||
type Provider_VerifTeeAttestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// VerifTeeAttestation is a helper method to define mock.On call
|
||||
// - report []byte
|
||||
// - teeNonce []byte
|
||||
func (_e *Provider_Expecter) VerifTeeAttestation(report interface{}, teeNonce interface{}) *Provider_VerifTeeAttestation_Call {
|
||||
return &Provider_VerifTeeAttestation_Call{Call: _e.mock.On("VerifTeeAttestation", report, teeNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifTeeAttestation_Call) Run(run func(report []byte, teeNonce []byte)) *Provider_VerifTeeAttestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte), args[1].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifTeeAttestation_Call) Return(_a0 error) *Provider_VerifTeeAttestation_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifTeeAttestation_Call) RunAndReturn(run func([]byte, []byte) error) *Provider_VerifTeeAttestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// VerifVTpmAttestation provides a mock function with given fields: report, vTpmNonce
|
||||
func (_m *Provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
ret := _m.Called(report, vTpmNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for VerifVTpmAttestation")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
|
||||
r0 = rf(report, vTpmNonce)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_VerifVTpmAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifVTpmAttestation'
|
||||
type Provider_VerifVTpmAttestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// VerifVTpmAttestation is a helper method to define mock.On call
|
||||
// - report []byte
|
||||
// - vTpmNonce []byte
|
||||
func (_e *Provider_Expecter) VerifVTpmAttestation(report interface{}, vTpmNonce interface{}) *Provider_VerifVTpmAttestation_Call {
|
||||
return &Provider_VerifVTpmAttestation_Call{Call: _e.mock.On("VerifVTpmAttestation", report, vTpmNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifVTpmAttestation_Call) Run(run func(report []byte, vTpmNonce []byte)) *Provider_VerifVTpmAttestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte), args[1].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifVTpmAttestation_Call) Return(_a0 error) *Provider_VerifVTpmAttestation_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifVTpmAttestation_Call) RunAndReturn(run func([]byte, []byte) error) *Provider_VerifVTpmAttestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// VerifyAttestation provides a mock function with given fields: report, teeNonce, vTpmNonce
|
||||
func (_m *Provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
ret := _m.Called(report, teeNonce, vTpmNonce)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for VerifyAttestation")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func([]byte, []byte, []byte) error); ok {
|
||||
r0 = rf(report, teeNonce, vTpmNonce)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Provider_VerifyAttestation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyAttestation'
|
||||
type Provider_VerifyAttestation_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// VerifyAttestation is a helper method to define mock.On call
|
||||
// - report []byte
|
||||
// - teeNonce []byte
|
||||
// - vTpmNonce []byte
|
||||
func (_e *Provider_Expecter) VerifyAttestation(report interface{}, teeNonce interface{}, vTpmNonce interface{}) *Provider_VerifyAttestation_Call {
|
||||
return &Provider_VerifyAttestation_Call{Call: _e.mock.On("VerifyAttestation", report, teeNonce, vTpmNonce)}
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifyAttestation_Call) Run(run func(report []byte, teeNonce []byte, vTpmNonce []byte)) *Provider_VerifyAttestation_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([]byte), args[1].([]byte), args[2].([]byte))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifyAttestation_Call) Return(_a0 error) *Provider_VerifyAttestation_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *Provider_VerifyAttestation_Call) RunAndReturn(run func([]byte, []byte, []byte) error) *Provider_VerifyAttestation_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewProvider(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Provider {
|
||||
mock := &Provider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//go:build embed
|
||||
// +build embed
|
||||
|
||||
package quoteprovider
|
||||
|
||||
import (
|
||||
"github.com/google/go-sev-guest/client"
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
pb "github.com/google/go-sev-guest/proto/sevsnp"
|
||||
cocosai "github.com/ultravioletrs/cocos"
|
||||
)
|
||||
|
||||
const Nonce = 64
|
||||
|
||||
var _ client.LeveledQuoteProvider = (*embeddedQuoteProvider)(nil)
|
||||
|
||||
type embeddedQuoteProvider struct {
|
||||
}
|
||||
|
||||
func GetLeveledQuoteProvider() (client.LeveledQuoteProvider, error) {
|
||||
return &embeddedQuoteProvider{}, nil
|
||||
}
|
||||
|
||||
// GetRawQuoteAtLevel returns the SEV quote for the given report data and VMPL.
|
||||
func (e *embeddedQuoteProvider) GetRawQuoteAtLevel(reportData [64]byte, vmpl uint) ([]byte, error) {
|
||||
return cocosai.EmbeddedAttestation, nil
|
||||
}
|
||||
|
||||
// IsSupported returns true if the SEV platform is supported.
|
||||
func (e *embeddedQuoteProvider) IsSupported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Product returns the SEV product information.
|
||||
// unimplemented since it is deprecated and not used.
|
||||
func (e *embeddedQuoteProvider) Product() *pb.SevProduct {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
||||
return cocosai.EmbeddedAttestation, nil
|
||||
}
|
||||
|
||||
func VerifyAttestationReportTLS(attestation *sevsnp.Attestation, reportData []byte) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
// Copyright (c) Ultraviolet
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by mockery v2.53.3. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
sevsnp "github.com/google/go-sev-guest/proto/sevsnp"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// LeveledQuoteProvider is an autogenerated mock type for the LeveledQuoteProvider type
|
||||
type LeveledQuoteProvider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type LeveledQuoteProvider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *LeveledQuoteProvider) EXPECT() *LeveledQuoteProvider_Expecter {
|
||||
return &LeveledQuoteProvider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// GetRawQuoteAtLevel provides a mock function with given fields: reportData, vmpl
|
||||
func (_m *LeveledQuoteProvider) GetRawQuoteAtLevel(reportData [64]byte, vmpl uint) ([]uint8, error) {
|
||||
ret := _m.Called(reportData, vmpl)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetRawQuoteAtLevel")
|
||||
}
|
||||
|
||||
var r0 []uint8
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([64]byte, uint) ([]uint8, error)); ok {
|
||||
return rf(reportData, vmpl)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([64]byte, uint) []uint8); ok {
|
||||
r0 = rf(reportData, vmpl)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]uint8)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([64]byte, uint) error); ok {
|
||||
r1 = rf(reportData, vmpl)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// LeveledQuoteProvider_GetRawQuoteAtLevel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRawQuoteAtLevel'
|
||||
type LeveledQuoteProvider_GetRawQuoteAtLevel_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetRawQuoteAtLevel is a helper method to define mock.On call
|
||||
// - reportData [64]byte
|
||||
// - vmpl uint
|
||||
func (_e *LeveledQuoteProvider_Expecter) GetRawQuoteAtLevel(reportData interface{}, vmpl interface{}) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
||||
return &LeveledQuoteProvider_GetRawQuoteAtLevel_Call{Call: _e.mock.On("GetRawQuoteAtLevel", reportData, vmpl)}
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) Run(run func(reportData [64]byte, vmpl uint)) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].([64]byte), args[1].(uint))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) Return(_a0 []uint8, _a1 error) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_GetRawQuoteAtLevel_Call) RunAndReturn(run func([64]byte, uint) ([]uint8, error)) *LeveledQuoteProvider_GetRawQuoteAtLevel_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// IsSupported provides a mock function with no fields
|
||||
func (_m *LeveledQuoteProvider) IsSupported() bool {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for IsSupported")
|
||||
}
|
||||
|
||||
var r0 bool
|
||||
if rf, ok := ret.Get(0).(func() bool); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// LeveledQuoteProvider_IsSupported_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSupported'
|
||||
type LeveledQuoteProvider_IsSupported_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// IsSupported is a helper method to define mock.On call
|
||||
func (_e *LeveledQuoteProvider_Expecter) IsSupported() *LeveledQuoteProvider_IsSupported_Call {
|
||||
return &LeveledQuoteProvider_IsSupported_Call{Call: _e.mock.On("IsSupported")}
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_IsSupported_Call) Run(run func()) *LeveledQuoteProvider_IsSupported_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_IsSupported_Call) Return(_a0 bool) *LeveledQuoteProvider_IsSupported_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_IsSupported_Call) RunAndReturn(run func() bool) *LeveledQuoteProvider_IsSupported_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Product provides a mock function with no fields
|
||||
func (_m *LeveledQuoteProvider) Product() *sevsnp.SevProduct {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Product")
|
||||
}
|
||||
|
||||
var r0 *sevsnp.SevProduct
|
||||
if rf, ok := ret.Get(0).(func() *sevsnp.SevProduct); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*sevsnp.SevProduct)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// LeveledQuoteProvider_Product_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Product'
|
||||
type LeveledQuoteProvider_Product_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Product is a helper method to define mock.On call
|
||||
func (_e *LeveledQuoteProvider_Expecter) Product() *LeveledQuoteProvider_Product_Call {
|
||||
return &LeveledQuoteProvider_Product_Call{Call: _e.mock.On("Product")}
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_Product_Call) Run(run func()) *LeveledQuoteProvider_Product_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_Product_Call) Return(_a0 *sevsnp.SevProduct) *LeveledQuoteProvider_Product_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *LeveledQuoteProvider_Product_Call) RunAndReturn(run func() *sevsnp.SevProduct) *LeveledQuoteProvider_Product_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewLeveledQuoteProvider creates a new instance of LeveledQuoteProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewLeveledQuoteProvider(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *LeveledQuoteProvider {
|
||||
mock := &LeveledQuoteProvider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -21,18 +21,16 @@ import (
|
||||
"github.com/google/go-sev-guest/verify"
|
||||
"github.com/google/go-sev-guest/verify/trust"
|
||||
"github.com/google/logger"
|
||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
cocosDirectory = ".cocos"
|
||||
caBundleName = "ask_ark.pem"
|
||||
attestationReportSize = 0x4A0
|
||||
Nonce = 64
|
||||
sevProductNameMilan = "Milan"
|
||||
sevProductNameGenoa = "Genoa"
|
||||
sevVMPL = 2
|
||||
cocosDirectory = ".cocos"
|
||||
caBundleName = "ask_ark.pem"
|
||||
Nonce = 64
|
||||
sevProductNameMilan = "Milan"
|
||||
sevProductNameGenoa = "Genoa"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -87,15 +85,7 @@ func verifyReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
||||
}
|
||||
|
||||
if cfg.Policy.Product == nil {
|
||||
productName := sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN
|
||||
switch cfg.RootOfTrust.ProductLine {
|
||||
case sevProductNameMilan:
|
||||
productName = sevsnp.SevProduct_SEV_PRODUCT_MILAN
|
||||
case sevProductNameGenoa:
|
||||
productName = sevsnp.SevProduct_SEV_PRODUCT_GENOA
|
||||
default:
|
||||
}
|
||||
|
||||
productName := GetProductName(cfg.RootOfTrust.ProductLine)
|
||||
if productName == sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN {
|
||||
return errProductLine
|
||||
}
|
||||
@@ -127,7 +117,7 @@ func verifyReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
||||
func validateReport(attestationPB *sevsnp.Attestation, cfg *check.Config) error {
|
||||
opts, err := validate.PolicyToOptions(cfg.Policy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get policy for validation %v", errors.Wrap(errAttVerification, err))
|
||||
return fmt.Errorf("failed to get policy for validation: %v", errors.Wrap(errAttVerification, err))
|
||||
}
|
||||
|
||||
if err = validate.SnpAttestation(attestationPB, opts); err != nil {
|
||||
@@ -142,7 +132,7 @@ func GetLeveledQuoteProvider() (client.LeveledQuoteProvider, error) {
|
||||
}
|
||||
|
||||
func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []byte) error {
|
||||
config, err := copyConfig(config.AttestationPolicy.Config)
|
||||
config, err := copyConfig(attestation.AttestationPolicy.Config)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to create a copy of attestation policy"), err)
|
||||
}
|
||||
@@ -150,7 +140,11 @@ func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []
|
||||
// Certificate chain is populated based on the extra data that is appended to the SEV-SNP attestation report.
|
||||
// This data is not part of the attestation report and it will be ignored.
|
||||
attestationPB.CertificateChain = nil
|
||||
config.Policy.ReportData = reportData[:]
|
||||
|
||||
if len(reportData) != 0 {
|
||||
config.Policy.ReportData = reportData[:]
|
||||
}
|
||||
|
||||
return VerifyAndValidate(attestationPB, config)
|
||||
}
|
||||
|
||||
@@ -168,7 +162,7 @@ func VerifyAndValidate(attestationPB *sevsnp.Attestation, cfg *check.Config) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
||||
func FetchAttestation(reportDataSlice []byte, vmpl uint) ([]byte, error) {
|
||||
var reportData [Nonce]byte
|
||||
|
||||
qp, err := GetLeveledQuoteProvider()
|
||||
@@ -181,10 +175,21 @@ func FetchAttestation(reportDataSlice []byte) ([]byte, error) {
|
||||
}
|
||||
copy(reportData[:], reportDataSlice)
|
||||
|
||||
rawQuote, err := qp.GetRawQuoteAtLevel(reportData, sevVMPL)
|
||||
rawQuote, err := qp.GetRawQuoteAtLevel(reportData, vmpl)
|
||||
if err != nil {
|
||||
return []byte{}, fmt.Errorf("failed to get raw quote")
|
||||
}
|
||||
|
||||
return rawQuote, nil
|
||||
}
|
||||
|
||||
func GetProductName(product string) sevsnp.SevProduct_SevProductName {
|
||||
switch product {
|
||||
case sevProductNameMilan:
|
||||
return sevsnp.SevProduct_SEV_PRODUCT_MILAN
|
||||
case sevProductNameGenoa:
|
||||
return sevsnp.SevProduct_SEV_PRODUCT_GENOA
|
||||
default:
|
||||
return sevsnp.SevProduct_SEV_PRODUCT_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ func prepVerifyAttReport(t *testing.T) (*sevsnp.Attestation, []byte) {
|
||||
file, err := os.ReadFile("../../../attestation.bin")
|
||||
require.NoError(t, err)
|
||||
|
||||
if len(file) < attestationReportSize {
|
||||
file = append(file, make([]byte, attestationReportSize-len(file))...)
|
||||
if len(file) < abi.ReportSize {
|
||||
file = append(file, make([]byte, abi.ReportSize-len(file))...)
|
||||
}
|
||||
|
||||
rr, err := abi.ReportCertsToProto(file)
|
||||
|
||||
+121
-87
@@ -8,7 +8,6 @@ import (
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -17,18 +16,22 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/google/go-sev-guest/abi"
|
||||
"github.com/google/go-sev-guest/proto/sevsnp"
|
||||
"github.com/google/go-tpm-tools/client"
|
||||
"github.com/google/go-tpm-tools/proto/attest"
|
||||
"github.com/google/go-tpm-tools/proto/tpm"
|
||||
ptpm "github.com/google/go-tpm-tools/proto/tpm"
|
||||
"github.com/google/go-tpm-tools/server"
|
||||
"github.com/google/go-tpm/legacy/tpm2"
|
||||
"github.com/google/go-tpm/tpmutil"
|
||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var _ attestation.Provider = (*provider)(nil)
|
||||
|
||||
const (
|
||||
eventLog = "/sys/kernel/security/tpm0/binary_bios_measurements"
|
||||
Nonce = 32
|
||||
@@ -41,24 +44,23 @@ const (
|
||||
var (
|
||||
ExternalTPM io.ReadWriteCloser
|
||||
ErrNoHashAlgo = errors.New("hash algo is not supported")
|
||||
ErrFetchQuote = errors.New("failed to fetch vTPM quote")
|
||||
)
|
||||
|
||||
type VtpmAttest func(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error)
|
||||
|
||||
type tpmWrapper struct {
|
||||
type tpm struct {
|
||||
io.ReadWriteCloser
|
||||
}
|
||||
|
||||
func (et tpmWrapper) EventLog() ([]byte, error) {
|
||||
func (et tpm) EventLog() ([]byte, error) {
|
||||
return os.ReadFile(eventLog)
|
||||
}
|
||||
|
||||
func OpenTpm() (io.ReadWriteCloser, error) {
|
||||
if ExternalTPM != nil {
|
||||
return tpmWrapper{ExternalTPM}, nil
|
||||
return tpm{ExternalTPM}, nil
|
||||
}
|
||||
|
||||
tw := tpmWrapper{}
|
||||
tw := tpm{}
|
||||
var err error
|
||||
|
||||
tw.ReadWriteCloser, err = tpm2.OpenTPM("/dev/tpmrm0")
|
||||
@@ -89,14 +91,65 @@ func ExtendPCR(pcrIndex int, value []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error) {
|
||||
attestation, err := fetchVTPMQuote(vTPMNonce)
|
||||
type provider struct {
|
||||
pubKey []byte
|
||||
teeAttestaion bool
|
||||
vmpl uint
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
func New(pubKey []byte, teeAttestation bool, vmpl uint, writer io.Writer) attestation.Provider {
|
||||
return &provider{
|
||||
pubKey: pubKey,
|
||||
teeAttestaion: teeAttestation,
|
||||
vmpl: vmpl,
|
||||
writer: writer,
|
||||
}
|
||||
}
|
||||
|
||||
func (v provider) Attestation(teeNonce []byte, vTpmNonce []byte) ([]byte, error) {
|
||||
return Attest(teeNonce, vTpmNonce, v.teeAttestaion, v.vmpl)
|
||||
}
|
||||
|
||||
func (v provider) TeeAttestation(teeNonce []byte) ([]byte, error) {
|
||||
return quoteprovider.FetchAttestation(teeNonce, v.vmpl)
|
||||
}
|
||||
|
||||
func (v provider) VTpmAttestation(vTpmNonce []byte) ([]byte, error) {
|
||||
quote, err := FetchQuote(vTpmNonce)
|
||||
if err != nil {
|
||||
return []byte{}, errors.Wrap(ErrFetchQuote, err)
|
||||
}
|
||||
|
||||
return proto.Marshal(quote)
|
||||
}
|
||||
|
||||
func (v provider) VerifTeeAttestation(report []byte, teeNonce []byte) error {
|
||||
attestReport, err := abi.ReportToProto(report)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||
}
|
||||
|
||||
attestationReport := sevsnp.Attestation{Report: attestReport, CertificateChain: nil}
|
||||
return quoteprovider.VerifyAttestationReportTLS(&attestationReport, teeNonce)
|
||||
}
|
||||
|
||||
func (v provider) VerifVTpmAttestation(report []byte, vTpmNonce []byte) error {
|
||||
return VerifyQuote(report, v.pubKey, vTpmNonce, v.writer)
|
||||
}
|
||||
|
||||
func (v provider) VerifyAttestation(report []byte, teeNonce []byte, vTpmNonce []byte) error {
|
||||
return VTPMVerify(report, v.pubKey, teeNonce, vTpmNonce, v.writer)
|
||||
}
|
||||
|
||||
func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool, vmpl uint) ([]byte, error) {
|
||||
attestation, err := FetchQuote(vTPMNonce)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
if teeAttestaion {
|
||||
attestation, err = addTEEAttestation(attestation, teeNonce)
|
||||
err = addTEEAttestation(attestation, teeNonce, vmpl)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
@@ -105,26 +158,26 @@ func Attest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, erro
|
||||
return marshalQuote(attestation)
|
||||
}
|
||||
|
||||
func FetchATLSQuote(pubKey, teeNonce, vTPMNonce []byte) ([]byte, error) {
|
||||
attestation, err := fetchVTPMQuote(vTPMNonce)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
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)
|
||||
}
|
||||
|
||||
reportData, err := createTEEAttestationReportNonce(pubKey, attestation.GetAkPub(), teeNonce)
|
||||
attestation := &attest.Attestation{}
|
||||
|
||||
err := proto.Unmarshal(quote, attestation)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return errors.Wrap(fmt.Errorf("failed to unmarshal quote"), err)
|
||||
}
|
||||
|
||||
attestation, err = addTEEAttestation(attestation, reportData)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), teeNonce); err != nil {
|
||||
return fmt.Errorf("failed to verify TEE attestation report: %v", err)
|
||||
}
|
||||
|
||||
return marshalQuote(attestation)
|
||||
return nil
|
||||
}
|
||||
|
||||
func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byte) error {
|
||||
func VerifyQuote(quote []byte, pubKeyTLS []byte, vtpmNonce []byte, writer io.Writer) error {
|
||||
attestation := &attest.Attestation{}
|
||||
|
||||
err := proto.Unmarshal(quote, attestation)
|
||||
@@ -143,16 +196,7 @@ func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byt
|
||||
return err
|
||||
}
|
||||
|
||||
reportData, err := createTEEAttestationReportNonce(pubKeyTLS, ak, teeNonce)
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to create TEE attestation report nonce"), err)
|
||||
}
|
||||
|
||||
if err := quoteprovider.VerifyAttestationReportTLS(attestation.GetSevSnpAttestation(), reportData); err != nil {
|
||||
return fmt.Errorf("failed to verify TEE attestation report: %v", err)
|
||||
}
|
||||
|
||||
_, err = server.VerifyAttestation(attestation, server.VerifyOpts{Nonce: vtpmNonce, TrustedAKs: []crypto.PublicKey{cryptoPub}})
|
||||
ms, err := server.VerifyAttestation(attestation, server.VerifyOpts{Nonce: vtpmNonce, TrustedAKs: []crypto.PublicKey{cryptoPub}})
|
||||
if err != nil {
|
||||
return errors.Wrap(fmt.Errorf("failed to verify attestation"), err)
|
||||
}
|
||||
@@ -163,44 +207,22 @@ func VTPMVerify(quote []byte, pubKeyTLS []byte, teeNonce []byte, vtpmNonce []byt
|
||||
return fmt.Errorf("PCR values do not match expected PCR values: %w", err)
|
||||
}
|
||||
|
||||
if writer != nil {
|
||||
marshalOptions := prototext.MarshalOptions{Multiline: true, EmitASCII: true}
|
||||
|
||||
out, err := marshalOptions.Marshal(ms)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := writer.Write(out); err != nil {
|
||||
return fmt.Errorf("failed to write verified attestation report: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmptyAttest is a dummy attestation function that returns an empty attestation report.
|
||||
func EmptyAttest(teeNonce []byte, vTPMNonce []byte, teeAttestaion bool) ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
func publicKeyToBytes(pubKey interface{}) ([]byte, error) {
|
||||
derBytes, err := x509.MarshalPKIXPublicKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return derBytes, nil
|
||||
}
|
||||
|
||||
func createTEEAttestationReportNonce(pubKeyTLS []byte, ak []byte, nonce []byte) ([]byte, error) {
|
||||
pub, err := tpm2.DecodePublic(ak)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
cryptoPub, err := pub.Key()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
pubKeyBytes, err := publicKeyToBytes(cryptoPub)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
reportData := append(append(pubKeyTLS, pubKeyBytes...), nonce...)
|
||||
hash := sha3.Sum512(reportData)
|
||||
|
||||
return hash[:], nil
|
||||
}
|
||||
|
||||
func marshalQuote(attestation *attest.Attestation) ([]byte, error) {
|
||||
out, err := proto.Marshal(attestation)
|
||||
if err != nil {
|
||||
@@ -210,7 +232,7 @@ func marshalQuote(attestation *attest.Attestation) ([]byte, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func fetchVTPMQuote(nonce []byte) (*attest.Attestation, error) {
|
||||
func FetchQuote(nonce []byte) (*attest.Attestation, error) {
|
||||
rwc, err := OpenTpm()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -241,46 +263,54 @@ func fetchVTPMQuote(nonce []byte) (*attest.Attestation, error) {
|
||||
return attestation, nil
|
||||
}
|
||||
|
||||
func addTEEAttestation(attestation *attest.Attestation, nonce []byte) (*attest.Attestation, error) {
|
||||
rawTeeAttestation, err := quoteprovider.FetchAttestation(nonce)
|
||||
func addTEEAttestation(attestation *attest.Attestation, nonce []byte, vmpl uint) error {
|
||||
rawTeeAttestation, err := quoteprovider.FetchAttestation(nonce, vmpl)
|
||||
if err != nil {
|
||||
return attestation, fmt.Errorf("failed to fetch TEE attestation report: %v", err)
|
||||
return fmt.Errorf("failed to fetch TEE attestation report: %v", err)
|
||||
}
|
||||
|
||||
extReport, err := abi.ReportCertsToProto(rawTeeAttestation)
|
||||
if err != nil {
|
||||
return attestation, errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||
return errors.Wrap(fmt.Errorf("failed to convert TEE report to proto"), err)
|
||||
}
|
||||
attestation.TeeAttestation = &attest.Attestation_SevSnpAttestation{
|
||||
SevSnpAttestation: extReport,
|
||||
}
|
||||
|
||||
return attestation, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []byte) error {
|
||||
quotes := attestation.GetQuotes()
|
||||
func checkExpectedPCRValues(attQuote *attest.Attestation, ePcr256, ePcr384 []byte) error {
|
||||
quotes := attQuote.GetQuotes()
|
||||
for i := range quotes {
|
||||
quote := quotes[i]
|
||||
var pcrMap map[string]string
|
||||
var pcr15 []byte
|
||||
switch quote.Pcrs.Hash {
|
||||
case tpm.HashAlgo_SHA256:
|
||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha256
|
||||
pcr15 = ePcr256
|
||||
case tpm.HashAlgo_SHA384:
|
||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha384
|
||||
pcr15 = ePcr384
|
||||
case tpm.HashAlgo_SHA1:
|
||||
pcrMap = config.AttestationPolicy.PcrConfig.PCRValues.Sha1
|
||||
case ptpm.HashAlgo_SHA256:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha256
|
||||
if ePcr256 == nil {
|
||||
pcr15 = make([]byte, 32)
|
||||
} else {
|
||||
pcr15 = ePcr256
|
||||
}
|
||||
case ptpm.HashAlgo_SHA384:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha384
|
||||
if ePcr384 == nil {
|
||||
pcr15 = make([]byte, 48)
|
||||
} else {
|
||||
pcr15 = ePcr384
|
||||
}
|
||||
case ptpm.HashAlgo_SHA1:
|
||||
pcrMap = attestation.AttestationPolicy.PcrConfig.PCRValues.Sha1
|
||||
pcr15 = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
default:
|
||||
return errors.Wrap(ErrNoHashAlgo, fmt.Errorf("algo: %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)]))
|
||||
return errors.Wrap(ErrNoHashAlgo, fmt.Errorf("algo: %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)]))
|
||||
}
|
||||
|
||||
pcr15Index := uint32(15)
|
||||
if !bytes.Equal(quote.Pcrs.Pcrs[pcr15Index], pcr15) {
|
||||
return fmt.Errorf("for algo %s PCR[15] expected %s but found %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)], hex.EncodeToString(pcr15), hex.EncodeToString(quote.Pcrs.Pcrs[pcr15Index]))
|
||||
return fmt.Errorf("for algo %s PCR[15] expected %s but found %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)], hex.EncodeToString(pcr15), hex.EncodeToString(quote.Pcrs.Pcrs[pcr15Index]))
|
||||
}
|
||||
|
||||
for i, v := range pcrMap {
|
||||
@@ -293,7 +323,7 @@ func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []
|
||||
return errors.Wrap(fmt.Errorf("error converting PCR value to byte"), err)
|
||||
}
|
||||
if !bytes.Equal(quote.Pcrs.Pcrs[uint32(index)], value) {
|
||||
return fmt.Errorf("for algo %s PCR[%d] expected %s but found %s", tpm.HashAlgo_name[int32(quote.Pcrs.Hash)], index, hex.EncodeToString(value), hex.EncodeToString(quote.Pcrs.Pcrs[uint32(index)]))
|
||||
return fmt.Errorf("for algo %s PCR[%d] expected %s but found %s", ptpm.HashAlgo_name[int32(quote.Pcrs.Hash)], index, hex.EncodeToString(value), hex.EncodeToString(quote.Pcrs.Pcrs[uint32(index)]))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,6 +332,10 @@ func checkExpectedPCRValues(attestation *attest.Attestation, ePcr256, ePcr384 []
|
||||
|
||||
// Return SHA256 and SHA384 values of the input public key.
|
||||
func calculatePCRTLSKey(pubKey []byte) ([]byte, []byte) {
|
||||
if len(pubKey) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
init256 := make([]byte, Hash256)
|
||||
init384 := make([]byte, Hash384)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent/mocks"
|
||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
pkggrpc "github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/health"
|
||||
@@ -113,7 +113,7 @@ func TestAgentClientIntegration(t *testing.T) {
|
||||
},
|
||||
AttestedTLS: true,
|
||||
},
|
||||
err: config.ErrAttestationPolicyMissing,
|
||||
err: attestation.ErrAttestationPolicyMissing,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ import (
|
||||
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/ultravioletrs/cocos/pkg/atls"
|
||||
config "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
func setupATLS(cfg AgentClientConfig) (credentials.TransportCredentials, error) {
|
||||
err := config.ReadAttestationPolicy(cfg.AttestationPolicy, &config.AttestationPolicy)
|
||||
err := attestation.ReadAttestationPolicy(cfg.AttestationPolicy, &attestation.AttestationPolicy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(fmt.Errorf("failed to read Attestation Policy"), err)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/google/go-sev-guest/proto/check"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
att "github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation"
|
||||
)
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
@@ -221,25 +221,25 @@ func TestReadAttestationPolicy(t *testing.T) {
|
||||
name: "Invalid JSON",
|
||||
manifestPath: "invalid_manifest.json",
|
||||
fileContent: invalidJSON,
|
||||
err: att.ErrAttestationPolicyDecode,
|
||||
err: attestation.ErrAttestationPolicyDecode,
|
||||
},
|
||||
{
|
||||
name: "Non-existent file",
|
||||
manifestPath: "nonexistent.json",
|
||||
fileContent: "",
|
||||
err: att.ErrAttestationPolicyOpen,
|
||||
err: attestation.ErrAttestationPolicyOpen,
|
||||
},
|
||||
{
|
||||
name: "Empty manifest path",
|
||||
manifestPath: "",
|
||||
fileContent: "",
|
||||
err: att.ErrAttestationPolicyMissing,
|
||||
err: attestation.ErrAttestationPolicyMissing,
|
||||
},
|
||||
{
|
||||
name: "Invalid JSON PCR",
|
||||
manifestPath: "invalid_manifest.json",
|
||||
fileContent: invalidJSONPCR,
|
||||
err: att.ErrAttestationPolicyDecode,
|
||||
err: attestation.ErrAttestationPolicyDecode,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -251,8 +251,8 @@ func TestReadAttestationPolicy(t *testing.T) {
|
||||
defer os.Remove(tt.manifestPath)
|
||||
}
|
||||
|
||||
config := att.Config{Config: &check.Config{}, PcrConfig: &att.PcrConfig{}}
|
||||
err := att.ReadAttestationPolicy(tt.manifestPath, &config)
|
||||
config := attestation.Config{Config: &check.Config{}, PcrConfig: &attestation.PcrConfig{}}
|
||||
err := attestation.ReadAttestationPolicy(tt.manifestPath, &config)
|
||||
|
||||
assert.True(t, errors.Contains(err, tt.err), fmt.Sprintf("expected error %v, got %v", tt.err, err))
|
||||
if tt.err == nil {
|
||||
|
||||
+10
-10
@@ -27,16 +27,15 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
AttestationReportSize = 0x4A0
|
||||
WithATLS = "with aTLS"
|
||||
WithTLS = "with TLS"
|
||||
WithATLS = "with aTLS"
|
||||
WithTLS = "with TLS"
|
||||
)
|
||||
|
||||
var (
|
||||
errGrpcConnect = errors.New("failed to connect to grpc server")
|
||||
errGrpcClose = errors.New("failed to close grpc connection")
|
||||
errCertificateParse = errors.New("failed to parse x509 certificate")
|
||||
errAttVerification = errors.New("certificat is not sefl signed")
|
||||
errAttVerification = errors.New("certificat is not self signed")
|
||||
errFailedToLoadClientCertKey = errors.New("failed to load client certificate and key")
|
||||
errFailedToLoadRootCA = errors.New("failed to load root ca file")
|
||||
)
|
||||
@@ -57,6 +56,7 @@ type AgentClientConfig struct {
|
||||
BaseConfig
|
||||
AttestationPolicy string `env:"ATTESTATION_POLICY" envDefault:""`
|
||||
AttestedTLS bool `env:"ATTESTED_TLS" envDefault:"false"`
|
||||
ProductName string `env:"PRODUCT_NAME" envDefault:"Milan"`
|
||||
}
|
||||
|
||||
type ManagerClientConfig struct {
|
||||
@@ -147,7 +147,7 @@ func connect(cfg ClientConfiguration) (*grpc.ClientConn, security, error) {
|
||||
secure = withaTLS
|
||||
} else {
|
||||
conf := cfg.GetBaseConfig()
|
||||
transportCreds, err, sec := loadTLSConfig(conf.ServerCAFile, conf.ClientCert, conf.ClientKey)
|
||||
transportCreds, sec, err := loadTLSConfig(conf.ServerCAFile, conf.ClientCert, conf.ClientKey)
|
||||
if err != nil {
|
||||
return nil, secure, err
|
||||
}
|
||||
@@ -162,7 +162,7 @@ func connect(cfg ClientConfiguration) (*grpc.ClientConn, security, error) {
|
||||
return conn, secure, nil
|
||||
}
|
||||
|
||||
func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.TransportCredentials, error, security) {
|
||||
func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.TransportCredentials, security, error) {
|
||||
tlsConfig := &tls.Config{}
|
||||
secure := withoutTLS
|
||||
tc := insecure.NewCredentials()
|
||||
@@ -170,12 +170,12 @@ func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.Tran
|
||||
if serverCAFile != "" {
|
||||
rootCA, err := os.ReadFile(serverCAFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errFailedToLoadRootCA, err), secure
|
||||
return nil, secure, errors.Wrap(errFailedToLoadRootCA, err)
|
||||
}
|
||||
if len(rootCA) > 0 {
|
||||
capool := x509.NewCertPool()
|
||||
if !capool.AppendCertsFromPEM(rootCA) {
|
||||
return nil, fmt.Errorf("failed to append root ca to tls.Config"), secure
|
||||
return nil, secure, fmt.Errorf("failed to append root ca to tls.Config")
|
||||
}
|
||||
tlsConfig.RootCAs = capool
|
||||
secure = withTLS
|
||||
@@ -186,12 +186,12 @@ func loadTLSConfig(serverCAFile, clientCert, clientKey string) (credentials.Tran
|
||||
if clientCert != "" || clientKey != "" {
|
||||
certificate, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errFailedToLoadClientCertKey, err), secure
|
||||
return nil, secure, errors.Wrap(errFailedToLoadClientCertKey, err)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{certificate}
|
||||
secure = withmTLS
|
||||
tc = credentials.NewTLS(tlsConfig)
|
||||
}
|
||||
|
||||
return tc, nil, secure
|
||||
return tc, secure, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user