Skip to content

Commit

Permalink
go/runtime: Also re-attest based on MaxAttestationAge
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Feb 22, 2023
1 parent 07995cd commit 1cfafd0
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 56 deletions.
1 change: 1 addition & 0 deletions .changelog/5187.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/runtime: Also re-attest based on MaxAttestationAge
3 changes: 0 additions & 3 deletions go/common/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ var (
// signature fails verification.
ErrInvalidAttestationSignature = errors.New("node: invalid TEE attestation signature")

// ErrAttestationNotFresh is the error returned when the TEE attestation is
// not fresh enough.
ErrAttestationNotFresh = errors.New("node: TEE attestation not fresh enough")
// ErrAttestationFromFuture is the error returned when the TEE attestation appears
// to be from the future.
ErrAttestationFromFuture = errors.New("node: TEE attestation from the future")
Expand Down
4 changes: 2 additions & 2 deletions go/common/node/sgx.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ func (sa *SGXAttestation) verifyAttestationSignature(
if sa.Height > height {
return ErrAttestationFromFuture
}
if height-sa.Height > sc.MaxAttestationAge {
return ErrAttestationNotFresh
if age := height - sa.Height; age > sc.MaxAttestationAge {
return fmt.Errorf("node: TEE attestation not fresh enough (age: %d max: %d)", age, sc.MaxAttestationAge)
}

return nil
Expand Down
3 changes: 3 additions & 0 deletions go/runtime/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ type Runtime interface {
// response (which may be a failure).
Call(ctx context.Context, body *protocol.Body) (*protocol.Body, error)

// UpdateCapabilityTEE asks the runtime to update its CapabilityTEE with latest data.
UpdateCapabilityTEE(ctx context.Context) error

// WatchEvents subscribes to runtime status events.
WatchEvents(ctx context.Context) (<-chan *Event, pubsub.ClosableSubscription, error)

Expand Down
5 changes: 5 additions & 0 deletions go/runtime/host/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ func (r *runtime) Call(ctx context.Context, body *protocol.Body) (*protocol.Body
}
}

// Implements host.Runtime.
func (r *runtime) UpdateCapabilityTEE(ctx context.Context) error {
return nil
}

// Implements host.Runtime.
func (r *runtime) WatchEvents(ctx context.Context) (<-chan *host.Event, pubsub.ClosableSubscription, error) {
typedCh := make(chan *host.Event)
Expand Down
11 changes: 11 additions & 0 deletions go/runtime/host/multi/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ func (agg *Aggregate) Call(ctx context.Context, body *protocol.Body) (rsp *proto
return
}

// UpdateCapabilityTEE implements host.Runtime.
func (agg *Aggregate) UpdateCapabilityTEE(ctx context.Context) error {
agg.l.RLock()
defer agg.l.RUnlock()

if agg.active == nil {
return ErrNoActiveVersion
}
return agg.active.host.UpdateCapabilityTEE(ctx)
}

// WatchEvents implements host.Runtime.
func (agg *Aggregate) WatchEvents(ctx context.Context) (<-chan *host.Event, pubsub.ClosableSubscription, error) {
typedCh := make(chan *host.Event)
Expand Down
65 changes: 47 additions & 18 deletions go/runtime/host/sandbox/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/cenkalti/backoff/v4"
"github.com/eapache/channels"

"github.com/oasisprotocol/oasis-core/go/common"
cmnBackoff "github.com/oasisprotocol/oasis-core/go/common/backoff"
Expand Down Expand Up @@ -45,7 +46,7 @@ type Config struct {

// HostInitializer is a function that additionally initializes the runtime host. In case it is
// not specified a default function is used.
HostInitializer func(context.Context, host.Runtime, version.Version, process.Process, protocol.Connection) (*host.StartedEvent, error)
HostInitializer func(context.Context, *HostInitializerParams) (*host.StartedEvent, error)

// Logger is an optional logger to use with this provisioner. In case it is not specified a
// default logger will be created.
Expand All @@ -58,6 +59,16 @@ type Config struct {
InsecureNoSandbox bool
}

// HostInitializerParams contains parameters for the HostInitializer function.
type HostInitializerParams struct {
Runtime host.Runtime
Version version.Version
Process process.Process
Connection protocol.Connection

NotifyUpdateCapabilityTEE <-chan struct{}
}

type provisioner struct {
cfg Config
}
Expand All @@ -67,14 +78,15 @@ func (p *provisioner) NewRuntime(ctx context.Context, cfg host.Config) (host.Run
id := cfg.Bundle.Manifest.ID

r := &sandboxedRuntime{
cfg: p.cfg,
rtCfg: cfg,
id: id,
stopCh: make(chan struct{}),
quitCh: make(chan struct{}),
ctrlCh: make(chan interface{}, ctrlChannelBufferSize),
notifier: pubsub.NewBroker(false),
logger: p.cfg.Logger.With("runtime_id", id),
cfg: p.cfg,
rtCfg: cfg,
id: id,
stopCh: make(chan struct{}),
quitCh: make(chan struct{}),
ctrlCh: make(chan interface{}, ctrlChannelBufferSize),
notifier: pubsub.NewBroker(false),
notifyUpdateCapabilityTEE: channels.NewRingChannel(1),
logger: p.cfg.Logger.With("runtime_id", id),
}

return r, nil
Expand Down Expand Up @@ -103,6 +115,8 @@ type sandboxedRuntime struct {
conn protocol.Connection
notifier *pubsub.Broker

notifyUpdateCapabilityTEE *channels.RingChannel

logger *logging.Logger
}

Expand Down Expand Up @@ -151,6 +165,16 @@ func (r *sandboxedRuntime) Call(ctx context.Context, body *protocol.Body) (rsp *
return
}

// Implements host.Runtime.
func (r *sandboxedRuntime) UpdateCapabilityTEE(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
case r.notifyUpdateCapabilityTEE.In() <- struct{}{}:
}
return nil
}

// Implements host.Runtime.
func (r *sandboxedRuntime) WatchEvents(ctx context.Context) (<-chan *host.Event, pubsub.ClosableSubscription, error) {
typedCh := make(chan *host.Event)
Expand Down Expand Up @@ -356,10 +380,21 @@ func (r *sandboxedRuntime) startProcess() (err error) {
return fmt.Errorf("version mismatch (runtime reported: %s bundle: %s)", *rtVersion, bndVersion)
}

notifyUpdateCapabilityTEECh := make(chan struct{})
channels.Unwrap(r.notifyUpdateCapabilityTEE, notifyUpdateCapabilityTEECh)

hp := &HostInitializerParams{
Runtime: r,
Version: *rtVersion,
Process: p,
Connection: pc,
NotifyUpdateCapabilityTEE: notifyUpdateCapabilityTEECh,
}

// Perform configuration-specific host initialization.
exInitCtx, cancelExInit := context.WithTimeout(ctx, runtimeExtendedInitTimeout)
defer cancelExInit()
ev, err := r.cfg.HostInitializer(exInitCtx, r, *rtVersion, p, pc)
ev, err := r.cfg.HostInitializer(exInitCtx, hp)
if err != nil {
return fmt.Errorf("failed to initialize connection: %w", err)
}
Expand Down Expand Up @@ -559,15 +594,9 @@ func New(cfg Config) (host.Provisioner, error) {
}
// Use a default HostInitializer if none was provided.
if cfg.HostInitializer == nil {
cfg.HostInitializer = func(
ctx context.Context,
rt host.Runtime,
version version.Version,
p process.Process,
conn protocol.Connection,
) (*host.StartedEvent, error) {
cfg.HostInitializer = func(ctx context.Context, hp *HostInitializerParams) (*host.StartedEvent, error) {
return &host.StartedEvent{
Version: version,
Version: hp.Version,
}, nil
}
}
Expand Down
58 changes: 29 additions & 29 deletions go/runtime/host/sgx/sgx.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,28 +259,22 @@ func (s *sgxProvisioner) getSandboxConfig(rtCfg host.Config, socketPath, runtime
}, nil
}

func (s *sgxProvisioner) hostInitializer(
ctx context.Context,
rt host.Runtime,
version version.Version,
p process.Process,
conn protocol.Connection,
) (*host.StartedEvent, error) {
func (s *sgxProvisioner) hostInitializer(ctx context.Context, hp *sandbox.HostInitializerParams) (*host.StartedEvent, error) {
// Initialize TEE.
var err error
var ts *teeState
if ts, err = s.initCapabilityTEE(ctx, rt, conn, version); err != nil {
if ts, err = s.initCapabilityTEE(ctx, hp.Runtime, hp.Connection, hp.Version); err != nil {
return nil, fmt.Errorf("failed to initialize TEE: %w", err)
}
var capabilityTEE *node.CapabilityTEE
if capabilityTEE, err = s.updateCapabilityTEE(ctx, s.logger, ts, conn); err != nil {
if capabilityTEE, err = s.updateCapabilityTEE(ctx, s.logger, ts, hp.Connection); err != nil {
return nil, fmt.Errorf("failed to initialize TEE: %w", err)
}

go s.attestationWorker(ts, p, conn, version)
go s.attestationWorker(ts, hp)

return &host.StartedEvent{
Version: version,
Version: hp.Version,
CapabilityTEE: capabilityTEE,
}, nil
}
Expand Down Expand Up @@ -349,35 +343,41 @@ func (s *sgxProvisioner) updateCapabilityTEE(ctx context.Context, logger *loggin
return capabilityTEE, nil
}

func (s *sgxProvisioner) attestationWorker(ts *teeState, p process.Process, conn protocol.Connection, version version.Version) {
func (s *sgxProvisioner) attestationWorker(ts *teeState, hp *sandbox.HostInitializerParams) {
t := time.NewTicker(s.cfg.RuntimeAttestInterval)
defer t.Stop()

logger := s.logger.With("runtime_id", ts.runtimeID)

for {
select {
case <-p.Wait():
case <-hp.Process.Wait():
// Process has terminated.
return
case <-t.C:
// Update CapabilityTEE.
logger.Info("regenerating CapabilityTEE")

capabilityTEE, err := s.updateCapabilityTEE(context.Background(), logger, ts, conn)
if err != nil {
logger.Error("failed to regenerate CapabilityTEE",
"err", err,
)
continue
}

// Emit event about the updated CapabilityTEE.
ts.eventEmitter.EmitEvent(&host.Event{Updated: &host.UpdatedEvent{
Version: version,
CapabilityTEE: capabilityTEE,
}})
// Re-attest based on the configured interval.
case <-hp.NotifyUpdateCapabilityTEE:
// Re-attest when explicitly requested. Also reset the periodic ticker to make sure we
// don't needlessly re-attest too often.
t.Reset(s.cfg.RuntimeAttestInterval)
}

// Update CapabilityTEE.
logger.Info("regenerating CapabilityTEE")

capabilityTEE, err := s.updateCapabilityTEE(context.Background(), logger, ts, hp.Connection)
if err != nil {
logger.Error("failed to regenerate CapabilityTEE",
"err", err,
)
continue
}

// Emit event about the updated CapabilityTEE.
ts.eventEmitter.EmitEvent(&host.Event{Updated: &host.UpdatedEvent{
Version: hp.Version,
CapabilityTEE: capabilityTEE,
}})
}
}

Expand Down
Loading

0 comments on commit 1cfafd0

Please sign in to comment.