mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
COCOS-192 - Add support for attested TLS (#279)
* add draft tls extension * add client support for ipv6 * remove vscode * add evidence request server payload * clean up the code * add fetch and verify for quote provider * add build parameters for buildroot * change Makefile to always enable CGO * fix ci * add malloc check for NULL * add copyright * renamed files and fix cgo lint * fix cache test * fix server tests * remove ineffective assignment * fix no-TLS connection * add check for SSL_set_fd failure * add tests for verification of attestation * fix CI * fix failing tests * fix backend tests * remove commented code * separate verify and validate function * fix failing test * Simplify function name --------- Co-authored-by: ultraviolet <cocosai@ultraviolet.local.pragmatic-it.com>
This commit is contained in:
committed by
GitHub
parent
6f747190b9
commit
e372cfc219
@@ -11,7 +11,6 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -25,8 +24,8 @@ import (
|
||||
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
|
||||
"github.com/ultravioletrs/cocos/agent/auth"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
"github.com/ultravioletrs/cocos/pkg/atls"
|
||||
"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"
|
||||
@@ -45,6 +44,7 @@ const (
|
||||
notAfterYear = 1
|
||||
notAfterMonth = 0
|
||||
notAfterDay = 0
|
||||
nonceSize = 32
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -89,15 +89,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)
|
||||
}
|
||||
creds := grpc.Creds(insecure.NewCredentials())
|
||||
var listener net.Listener = nil
|
||||
|
||||
switch {
|
||||
case s.Config.AttestedTLS:
|
||||
certificateBytes, privateKeyBytes, err := generateCertificatesForATLS(s.quoteProvider)
|
||||
certificateBytes, privateKeyBytes, err := generateCertificatesForATLS()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create certificate: %w", err)
|
||||
}
|
||||
@@ -113,7 +110,17 @@ func (s *Server) Start() error {
|
||||
}
|
||||
|
||||
creds = grpc.Creds(credentials.NewTLS(tlsConfig))
|
||||
|
||||
listener, err = atls.Listen(
|
||||
s.Address,
|
||||
certificateBytes,
|
||||
privateKeyBytes,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create Listener for aTLS: %w", err)
|
||||
}
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s with Attested TLS", s.Name, s.Address))
|
||||
|
||||
case s.Config.CertFile != "" || s.Config.KeyFile != "":
|
||||
certificate, err := loadX509KeyPair(s.Config.CertFile, s.Config.KeyFile)
|
||||
if err != nil {
|
||||
@@ -161,7 +168,18 @@ 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:
|
||||
var err error
|
||||
|
||||
listener, err = net.Listen("tcp", s.Address)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to listen on port %s: %w", s.Address, err)
|
||||
}
|
||||
s.Logger.Info(fmt.Sprintf("%s service gRPC server listening at %s without TLS", s.Name, s.Address))
|
||||
}
|
||||
|
||||
@@ -237,24 +255,13 @@ func loadX509KeyPair(certfile, keyfile string) (tls.Certificate, error) {
|
||||
return tls.X509KeyPair(cert, key)
|
||||
}
|
||||
|
||||
func generateCertificatesForATLS(qp client.QuoteProvider) ([]byte, []byte, error) {
|
||||
func generateCertificatesForATLS() ([]byte, []byte, error) {
|
||||
curve := elliptic.P256()
|
||||
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate private/public key: %w", err)
|
||||
}
|
||||
|
||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to marshal the public key: %w", err)
|
||||
}
|
||||
|
||||
// The Attestation Report will be added as an X.509 certificate extension
|
||||
attestationReport, err := qp.GetRawQuote(sha3.Sum512(publicKeyBytes))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to fetch the attestation report: %w", err)
|
||||
}
|
||||
|
||||
certTemplate := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(202403311),
|
||||
Subject: pkix.Name{
|
||||
@@ -270,13 +277,6 @@ func generateCertificatesForATLS(qp client.QuoteProvider) ([]byte, []byte, error
|
||||
KeyUsage: x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: asn1.ObjectIdentifier{1, 2, 3, 4, 5, 6},
|
||||
Critical: false,
|
||||
Value: attestationReport,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
certDERBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, certTemplate, &privateKey.PublicKey, privateKey)
|
||||
|
||||
@@ -18,10 +18,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
authmocks "github.com/ultravioletrs/cocos/agent/mocks"
|
||||
"github.com/ultravioletrs/cocos/agent/quoteprovider/mocks"
|
||||
"github.com/ultravioletrs/cocos/internal/server"
|
||||
"github.com/ultravioletrs/cocos/pkg/attestation/quoteprovider/mocks"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
)
|
||||
@@ -139,7 +138,6 @@ func TestServerStartWithAttestedTLS(t *testing.T) {
|
||||
logger := slog.New(slog.NewTextHandler(logBuffer, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||
qp := new(mocks.QuoteProvider)
|
||||
authSvc := new(authmocks.Authenticator)
|
||||
qp.On("GetRawQuote", mock.Anything).Return([]byte("mock-quote"), nil)
|
||||
|
||||
srv := New(ctx, cancel, "TestServer", config, func(srv *grpc.Server) {}, logger, qp, authSvc)
|
||||
|
||||
@@ -158,7 +156,7 @@ func TestServerStartWithAttestedTLS(t *testing.T) {
|
||||
|
||||
cancel()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
|
||||
logContent := logBuffer.String()
|
||||
assert.Contains(t, logContent, "TestServer service gRPC server listening at localhost:0 with Attested TLS")
|
||||
|
||||
Reference in New Issue
Block a user