Skip to content

Commit

Permalink
go/runtime/host/sgx: Add support for SIGSTRUCTs
Browse files Browse the repository at this point in the history
For now this will just generate one, signed with the same key that
`runtime-loader` used to use (the Fortanix dummy key), but this will
also support using file backed signatures, once we have an idea on how
we are going to handle the process for such things.
  • Loading branch information
Yawning committed May 13, 2020
1 parent e5472b4 commit 029e714
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 14 deletions.
6 changes: 6 additions & 0 deletions .changelog/1707.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
go/runtime/host/sgx: Add support for SIGSTRUCTs

For now this will just generate one, signed with the same key that
`runtime-loader` used to use (the Fortanix dummy key), but this will
also support using file backed signatures, once we have an idea on how
we are going to handle the process for such things.
40 changes: 40 additions & 0 deletions go/common/sgx/sigstruct/debug_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package sigstruct

import (
"fmt"

"github.com/oasislabs/oasis-core/go/common/sgx"
)

// UnsafeDebugForEnclave returns the SIGSTRUCT corresponding to the provided
// SGX enclave binary, signed using the Fortanix Rust SDK's dummy signing key.
//
// This routine is deterministic, and MUST only ever be used for testing.
func UnsafeDebugForEnclave(sgxs []byte) ([]byte, error) {
// Note: The key is unavailable unless DontBlameOasis is enabled.
signingKey := sgx.UnsafeFortanixDummyKey()
if signingKey == nil {
return nil, fmt.Errorf("sgx/sigstruct: debug signing key unavailable")
}

var enclaveHash sgx.MrEnclave
if err := enclaveHash.FromSgxsBytes(sgxs); err != nil {
return nil, fmt.Errorf("sgx/sigstruct: failed to derive EnclaveHash: %w", err)
}

builder := New(
WithAttributes(sgx.Attributes{
Flags: sgx.AttributeDebug | sgx.AttributeMode64Bit,
Xfrm: 3, // X87, SSE ("XFRM[1:0] must be set to 0x3")
}),
WithAttributesMask([2]uint64{^uint64(0), ^uint64(0)}),
WithEnclaveHash(enclaveHash),
)

ret, err := builder.Sign(signingKey)
if err != nil {
return nil, fmt.Errorf("sgx/sigstruct: failed to sign with test key: %w", err)
}

return ret, nil
}
16 changes: 11 additions & 5 deletions go/runtime/host/sandbox/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const (
type Config struct {
// GetSandboxConfig is a function that generates the sandbox configuration. In case it is not
// specified a default function is used.
GetSandboxConfig func(cfg host.Config, socketPath string, runtimeDir string) process.Config
GetSandboxConfig func(cfg host.Config, socketPath string, runtimeDir string) (process.Config, error)

// HostInitializer is a function that additionally initializes the runtime host. In case it is
// not specified a default function is used.
Expand Down Expand Up @@ -198,15 +198,21 @@ func (r *sandboxedRuntime) startProcess() (err error) {
// No sandbox.
r.logger.Warn("starting an UNSANDBOXED runtime")

cfg := r.cfg.GetSandboxConfig(r.rtCfg, hostSocket, runtimeDir)
cfg, cErr := r.cfg.GetSandboxConfig(r.rtCfg, hostSocket, runtimeDir)
if cErr != nil {
return fmt.Errorf("failed to configure process: %w", cErr)
}

p, err = process.NewNaked(cfg)
if err != nil {
return fmt.Errorf("failed to spawn process: %w", err)
}
case false:
// With sandbox.
cfg := r.cfg.GetSandboxConfig(r.rtCfg, bindHostSocketPath, runtimeDir)
cfg, cErr := r.cfg.GetSandboxConfig(r.rtCfg, bindHostSocketPath, runtimeDir)
if cErr != nil {
return fmt.Errorf("failed to configure sandbox: %w", cErr)
}

if cfg.BindRW == nil {
cfg.BindRW = make(map[string]string)
Expand Down Expand Up @@ -475,13 +481,13 @@ func (r *sandboxedRuntime) manager() {
func New(cfg Config) (host.Provisioner, error) {
// Use a default GetSandboxConfig if none was provided.
if cfg.GetSandboxConfig == nil {
cfg.GetSandboxConfig = func(cfg host.Config, socketPath string, runtimeDir string) process.Config {
cfg.GetSandboxConfig = func(cfg host.Config, socketPath string, runtimeDir string) (process.Config, error) {
return process.Config{
Path: cfg.Path,
Env: map[string]string{
"OASIS_WORKER_HOST": socketPath,
},
}
}, nil
}
}
// Use a default HostInitializer if none was provided.
Expand Down
81 changes: 72 additions & 9 deletions go/runtime/host/sgx/sgx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@
package sgx

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"path/filepath"
"sync"
"time"

"github.com/oasislabs/oasis-core/go/common"
"github.com/oasislabs/oasis-core/go/common/cbor"
"github.com/oasislabs/oasis-core/go/common/logging"
"github.com/oasislabs/oasis-core/go/common/node"
"github.com/oasislabs/oasis-core/go/common/sgx"
"github.com/oasislabs/oasis-core/go/common/sgx/aesm"
cmnIAS "github.com/oasislabs/oasis-core/go/common/sgx/ias"
"github.com/oasislabs/oasis-core/go/common/sgx/sigstruct"
"github.com/oasislabs/oasis-core/go/common/version"
ias "github.com/oasislabs/oasis-core/go/ias/api"
"github.com/oasislabs/oasis-core/go/runtime/host"
Expand All @@ -26,7 +32,8 @@ const (
// TODO: Support different locations for the AESMD socket.
aesmdSocketPath = "/var/run/aesmd/aesm.socket"

sandboxMountRuntime = "/runtime"
sandboxMountRuntime = "/runtime"
sandboxMountSignature = "/runtime.sig"

// Runtime RAK initialization timeout.
//
Expand All @@ -53,6 +60,12 @@ type Config struct {
InsecureNoSandbox bool
}

// RuntimeExtra is the extra configuration for SGX runtimes.
type RuntimeExtra struct {
// SignaturePath is the path to the runtime (enclave) SIGSTRUCT.
SignaturePath string
}

type teeState struct {
runtimeID common.Namespace
eventEmitter host.RuntimeEventEmitter
Expand All @@ -74,30 +87,80 @@ type sgxProvisioner struct {
logger *logging.Logger
}

func (s *sgxProvisioner) getSandboxConfig(rtCfg host.Config, socketPath string, runtimeDir string) process.Config {
runtimePath := rtCfg.Path
if !s.cfg.InsecureNoSandbox {
runtimePath = sandboxMountRuntime
func loadEnclaveBinaries(rtCfg host.Config) ([]byte, []byte, error) {
var (
sig, sgxs []byte
enclaveHash sgx.MrEnclave
err error
)

if sgxs, err = ioutil.ReadFile(rtCfg.Path); err != nil {
return nil, nil, fmt.Errorf("failed to load enclave: %w", err)
}
if err = enclaveHash.FromSgxsBytes(sgxs); err != nil {
return nil, nil, fmt.Errorf("failed to derive EnclaveHash: %w", err)
}

// If the path to an existing SIGSTRUCT is provided, load it.
if rtExtra, ok := rtCfg.Extra.(*RuntimeExtra); ok {
sig, err = ioutil.ReadFile(rtExtra.SignaturePath)
if err != nil {
return nil, nil, fmt.Errorf("failed to load SIGSTRUCT: %w", err)
}
} else {
// HACK: Just generate one with the test key for now.
if sig, err = sigstruct.UnsafeDebugForEnclave(sgxs); err != nil {
return nil, nil, fmt.Errorf("failed to generate debug SIGSTRUCT: %w", err)
}
}

_, parsed, err := sigstruct.Verify(sig)
if err != nil {
return nil, nil, fmt.Errorf("failed to validate SIGSTRUCT: %w", err)
}
if parsed.EnclaveHash != enclaveHash {
return nil, nil, fmt.Errorf("enclave/SIGSTRUCT mismatch")
}

return sgxs, sig, nil
}

func (s *sgxProvisioner) getSandboxConfig(rtCfg host.Config, socketPath string, runtimeDir string) (process.Config, error) {
// To try to avoid bad things from happening if the signature/enclave
// binaries change out from under us, and because the enclave binary
// needs to be loaded into memory anyway, this always injects
// (or copies).
runtimePath, signaturePath := sandboxMountRuntime, sandboxMountSignature
if s.cfg.InsecureNoSandbox {
runtimePath = filepath.Join(runtimeDir, runtimePath)
signaturePath = filepath.Join(runtimeDir, signaturePath)
}

sgxs, sig, err := loadEnclaveBinaries(rtCfg)
if err != nil {
return process.Config{}, fmt.Errorf("host/sgx: failed to load enclave/signature: %w", err)
}

return process.Config{
Path: s.cfg.LoaderPath,
Args: []string{
"--host-socket", socketPath,
"--type", "sgxs",
"--signature", signaturePath,
runtimePath,
},
BindRO: map[string]string{
rtCfg.Path: sandboxMountRuntime,
},
BindRW: map[string]string{
aesmdSocketPath: "/var/run/aesmd/aesm.socket",
},
BindDev: map[string]string{
// TODO: Support different kinds of SGX drivers.
"/dev/isgx": "/dev/isgx",
},
}
BindData: map[string]io.Reader{
runtimePath: bytes.NewReader(sgxs),
signaturePath: bytes.NewReader(sig),
},
}, nil
}

func (s *sgxProvisioner) hostInitializer(
Expand Down

0 comments on commit 029e714

Please sign in to comment.