Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COCOS-192 - Attested TLS #279

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions internal/server/grpc/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
"github.com/ultravioletrs/cocos/agent/auth"
"github.com/ultravioletrs/cocos/internal/server"
atls "github.com/ultravioletrs/cocos/pkg/tls_extensions"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"golang.org/x/crypto/sha3"
"google.golang.org/grpc"
Expand Down Expand Up @@ -85,11 +86,12 @@ func (s *Server) Start() error {
grpcServerOptions = append(grpcServerOptions, grpc.StreamInterceptor(stream))
}

listener, err := net.Listen("tcp", s.Address)
if err != nil {
return fmt.Errorf("failed to listen on port %s: %w", s.Address, err)
}
// listener, err := net.Listen("tcp", s.Address)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

// if err != nil {
// return fmt.Errorf("failed to listen on port %s: %w", s.Address, err)
// }
creds := grpc.Creds(insecure.NewCredentials())
var listener net.Listener = nil

switch {
case s.Config.AttestedTLS:
Expand All @@ -110,6 +112,16 @@ func (s *Server) Start() error {

creds = grpc.Creds(credentials.NewTLS(tlsConfig))
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with Attested TLS", s.Name, s.Address))
fmt.Printf("Listening on address: %s\n", s.Address)
listener, err = atls.Listen(
s.Address,
certificateBytes,
privateKeyBytes,
)
if err != nil {
return fmt.Errorf("failed to create Listener for aTLS: %w", err)
}

case s.Config.CertFile != "" || s.Config.KeyFile != "":
certificate, err := loadX509KeyPair(s.Config.CertFile, s.Config.KeyFile)
if err != nil {
Expand Down Expand Up @@ -157,6 +169,11 @@ func (s *Server) Start() error {
default:
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with TLS cert %s and key %s", s.Name, s.Address, s.Config.CertFile, s.Config.KeyFile))
}

listener, err = net.Listen("tcp", s.Address)
if err != nil {
return fmt.Errorf("failed to listen on port %s: %w", s.Address, err)
}
default:
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s without TLS", s.Name, s.Address))
}
Expand Down
2 changes: 1 addition & 1 deletion manager/agentEventsLogs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

const (
ManagerVsockPort = 9997
ManagerVsockPort = 9998 // TODO: Change to default
messageSize int = 1024
)

Expand Down
2 changes: 1 addition & 1 deletion manager/qemu/vsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/ultravioletrs/cocos/agent"
)

const VsockConfigPort uint32 = 9999
const VsockConfigPort uint32 = 7777 // TODO: Change to default

func (v *qemuVM) SendAgentConfig(ac agent.Computation) error {
conn, err := vsock.Dial(uint32(v.config.GuestCID), VsockConfigPort, nil)
Expand Down
258 changes: 127 additions & 131 deletions pkg/clients/grpc/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,15 @@
import (
"crypto/tls"
"crypto/x509"
"encoding/asn1"
"encoding/json"
"fmt"
"os"
"path"
"time"

"github.com/absmach/magistrala/pkg/errors"
"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/proto/check"
"github.com/google/go-sev-guest/proto/sevsnp"
"github.com/google/go-sev-guest/validate"
"github.com/google/go-sev-guest/verify"
"github.com/google/go-sev-guest/verify/trust"
atls "github.com/ultravioletrs/cocos/pkg/tls_extensions"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"golang.org/x/crypto/sha3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
Expand All @@ -34,31 +27,31 @@
withmTLS
)

const (
cocosDirectory = ".cocos"
caBundleName = "ask_ark.pem"
productNameMilan = "Milan"
productNameGenoa = "Genoa"
attestationReportSize = 0x4A0
)
// const (
// cocosDirectory = ".cocos"
// caBundleName = "ask_ark.pem"
// productNameMilan = "Milan"
// productNameGenoa = "Genoa"
// attestationReportSize = 0x4A0
// )

var (
errGrpcConnect = errors.New("failed to connect to grpc server")
errGrpcClose = errors.New("failed to close grpc connection")
errManifestOpen = errors.New("failed to open Manifest")
errManifestMissing = errors.New("failed due to missing Manifest")
errManifestDecode = errors.New("failed to decode Manifest json")
errCertificateParse = errors.New("failed to parse x509 certificate")
errAttVerification = errors.New("attestation verification failed")
errAttValidation = errors.New("attestation validation failed")
errCustomExtension = errors.New("failed due to missing custom extension")
errGrpcConnect = errors.New("failed to connect to grpc server")
errGrpcClose = errors.New("failed to close grpc connection")
errManifestOpen = errors.New("failed to open Manifest")
errManifestMissing = errors.New("failed due to missing Manifest")
errManifestDecode = errors.New("failed to decode Manifest json")
// errCertificateParse = errors.New("failed to parse x509 certificate")
// errAttVerification = errors.New("attestation verification failed")
// errAttValidation = errors.New("attestation validation failed")
// errCustomExtension = errors.New("failed due to missing custom extension")

Check failure on line 47 in pkg/clients/grpc/connect.go

View workflow job for this annotation

GitHub Actions / ci

Comment should end in a period (godot)
)

var (
customSEVSNPExtensionOID = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6}
// customSEVSNPExtensionOID = asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6}

Check failure on line 51 in pkg/clients/grpc/connect.go

View workflow job for this annotation

GitHub Actions / ci

Comment should end in a period (godot)
attestationConfiguration = AttestationConfiguration{}
timeout = time.Minute * 2
maxTryDelay = time.Second * 30
// timeout = time.Minute * 2
// maxTryDelay = time.Second * 30

Check failure on line 54 in pkg/clients/grpc/connect.go

View workflow job for this annotation

GitHub Actions / ci

Comment should end in a period (godot)
)

type Config struct {
Expand Down Expand Up @@ -185,6 +178,7 @@
}

opts = append(opts, grpc.WithTransportCredentials(tc))
opts = append(opts, grpc.WithContextDialer(atls.CustomDialer))

conn, err := grpc.NewClient(cfg.URL, opts...)
if err != nil {
Expand Down Expand Up @@ -214,111 +208,113 @@
}

func verifyAttestationReportTLS(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
cert, err := x509.ParseCertificate(rawCerts[0])
if err != nil {
return errors.Wrap(errCertificateParse, err)
}

for _, ext := range cert.Extensions {
if ext.Id.Equal(customSEVSNPExtensionOID) {
// Check if the certificate is self-signed
err := checkIfCertificateSelfSigned(cert)
if err != nil {
return errors.Wrap(errAttVerification, err)
}

publicKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
if err != nil {
return errors.Wrap(errAttVerification, err)
}

expectedReportData := sha3.Sum512(publicKeyBytes)
attestationConfiguration.SNPPolicy.ReportData = expectedReportData[:]

// Attestation verification and validation
sopts, err := verify.RootOfTrustToOptions(attestationConfiguration.RootOfTrust)
if err != nil {
return errors.Wrap(errAttVerification, err)
}

sopts.Product = attestationConfiguration.SNPPolicy.Product
sopts.Getter = &trust.RetryHTTPSGetter{
Timeout: timeout,
MaxRetryDelay: maxTryDelay,
Getter: &trust.SimpleHTTPSGetter{},
}

attestation_bytes := ext.Value[:attestationReportSize]
attestationPB, err := abi.ReportCertsToProto(attestation_bytes)
if err != nil {
return errors.Wrap(errAttVerification, err)
}

if err := fillInAttestationLocal(attestationPB); err != nil {
return err
}

if err = verify.SnpAttestation(attestationPB, sopts); err != nil {
return errors.Wrap(errAttVerification, err)
}

opts, err := validate.PolicyToOptions(attestationConfiguration.SNPPolicy)
if err != nil {
return errors.Wrap(errAttVerification, err)
}

if err = validate.SnpAttestation(attestationPB, opts); err != nil {
return errors.Wrap(errAttValidation, err)
}

return nil
}
}

return errCustomExtension
}

func checkIfCertificateSelfSigned(cert *x509.Certificate) error {
certPool := x509.NewCertPool()
certPool.AddCert(cert)

opts := x509.VerifyOptions{
Roots: certPool,
CurrentTime: time.Now(),
}

if _, err := cert.Verify(opts); err != nil {
return err
}
fmt.Println("verifyAttestationReportTLS called!")
// cert, err := x509.ParseCertificate(rawCerts[0])
// if err != nil {
// return errors.Wrap(errCertificateParse, err)
// }

// for _, ext := range cert.Extensions {
// if ext.Id.Equal(customSEVSNPExtensionOID) {
// // Check if the certificate is self-signed
// err := checkIfCertificateSelfSigned(cert)
// if err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// publicKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
// if err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// expectedReportData := sha3.Sum512(publicKeyBytes)
// attestationConfiguration.SNPPolicy.ReportData = expectedReportData[:]

// // Attestation verification and validation
// sopts, err := verify.RootOfTrustToOptions(attestationConfiguration.RootOfTrust)
// if err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// sopts.Product = attestationConfiguration.SNPPolicy.Product
// sopts.Getter = &trust.RetryHTTPSGetter{
// Timeout: timeout,
// MaxRetryDelay: maxTryDelay,
// Getter: &trust.SimpleHTTPSGetter{},
// }

// attestation_bytes := ext.Value[:attestationReportSize]
// attestationPB, err := abi.ReportCertsToProto(attestation_bytes)
// if err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// if err := fillInAttestationLocal(attestationPB); err != nil {
// return err
// }

// if err = verify.SnpAttestation(attestationPB, sopts); err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// opts, err := validate.PolicyToOptions(attestationConfiguration.SNPPolicy)
// if err != nil {
// return errors.Wrap(errAttVerification, err)
// }

// if err = validate.SnpAttestation(attestationPB, opts); err != nil {
// return errors.Wrap(errAttValidation, err)
// }

// return nil
// }
// }

return nil
// return errCustomExtension
}

func fillInAttestationLocal(attestation *sevsnp.Attestation) error {
product := attestationConfiguration.RootOfTrust.ProductLine

chain := attestation.GetCertificateChain()
if chain == nil {
chain = &sevsnp.CertificateChain{}
attestation.CertificateChain = chain
}
if len(chain.GetAskCert()) == 0 || len(chain.GetArkCert()) == 0 {
homePath, err := os.UserHomeDir()
if err != nil {
return err
}

bundleFilePath := path.Join(homePath, cocosDirectory, product, caBundleName)
if _, err := os.Stat(bundleFilePath); err == nil {
amdRootCerts := trust.AMDRootCerts{}
if err := amdRootCerts.FromKDSCert(bundleFilePath); err != nil {
return err
}

chain.ArkCert = amdRootCerts.ProductCerts.Ark.Raw
chain.AskCert = amdRootCerts.ProductCerts.Ask.Raw
}
}

return nil
}
// func checkIfCertificateSelfSigned(cert *x509.Certificate) error {
// certPool := x509.NewCertPool()
// certPool.AddCert(cert)

// opts := x509.VerifyOptions{
// Roots: certPool,
// CurrentTime: time.Now(),
// }

// if _, err := cert.Verify(opts); err != nil {
// return err
// }

// return nil
// }

// func fillInAttestationLocal(attestation *sevsnp.Attestation) error {
// product := attestationConfiguration.RootOfTrust.ProductLine

// chain := attestation.GetCertificateChain()
// if chain == nil {
// chain = &sevsnp.CertificateChain{}
// attestation.CertificateChain = chain
// }
// if len(chain.GetAskCert()) == 0 || len(chain.GetArkCert()) == 0 {
// homePath, err := os.UserHomeDir()
// if err != nil {
// return err
// }

// bundleFilePath := path.Join(homePath, cocosDirectory, product, caBundleName)
// if _, err := os.Stat(bundleFilePath); err == nil {
// amdRootCerts := trust.AMDRootCerts{}
// if err := amdRootCerts.FromKDSCert(bundleFilePath); err != nil {
// return err
// }

// chain.ArkCert = amdRootCerts.ProductCerts.Ark.Raw
// chain.AskCert = amdRootCerts.ProductCerts.Ask.Raw
// }
// }

// return nil
// }
Loading
Loading