Skip to content

Commit

Permalink
Merge pull request #5861 from oasisprotocol/kostko/feature/tdx-provis…
Browse files Browse the repository at this point in the history
…ioner

Add QEMU-based Intel TDX provisioner
  • Loading branch information
kostko authored Oct 9, 2024
2 parents 807b24d + bee88dc commit 456a688
Show file tree
Hide file tree
Showing 71 changed files with 5,745 additions and 1,320 deletions.
8 changes: 6 additions & 2 deletions .buildkite/rust/test_generic.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ unset OASIS_UNSAFE_SKIP_AVR_VERIFY
# Run the build and tests
#########################
pushd $src_dir
CARGO_TARGET_DIR="${CARGO_TARGET_DIR}/default" cargo build --release --all --locked --exclude simple-keyvalue
CARGO_TARGET_DIR="${CARGO_TARGET_DIR}/default" cargo build --release --workspace --locked \
--exclude simple-keyvalue

cargo fmt -- --check
CARGO_TARGET_DIR="${CARGO_TARGET_DIR}/default" cargo test --all --locked --exclude simple-keyvalue

CARGO_TARGET_DIR="${CARGO_TARGET_DIR}/default" cargo test --workspace --locked \
--exclude simple-keyvalue
popd
1 change: 1 addition & 0 deletions .changelog/5861.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add QEMU-based Intel TDX provisioner
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ members = [
"tests/runtimes/simple-keymanager",
"tests/runtimes/simple-rofl",
]
exclude = [
# Example TDX runtime.
"tests/runtimes/simple-rofl-tdx",
]
resolver = "2"

[profile.release]
Expand Down
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,19 @@ fmt: $(fmt-targets)
# Lint code, commits and documentation.
lint-targets := lint-rust lint-go lint-git lint-md lint-changelog lint-docs lint-go-mod-tidy

lint-rust:
@$(ECHO) "$(CYAN)*** Running cargo clippy linters...$(OFF)"
@cargo clippy --all-features -- -D warnings \
CARGO_CLIPPY_FLAGS := -D warnings \
-A clippy::upper-case-acronyms \
-A clippy::borrowed-box \
-A clippy::ptr-arg \
-A clippy::large_enum_variant \
-A clippy::field-reassign-with-default

lint-rust:
@$(ECHO) "$(CYAN)*** Running cargo clippy linters...$(OFF)"
@cargo clippy -- $(CARGO_CLIPPY_FLAGS)
@cargo clippy --features debug-mock-sgx -- $(CARGO_CLIPPY_FLAGS)
@cargo clippy --features tdx -- $(CARGO_CLIPPY_FLAGS)

lint-go:
@$(MAKE) -C go lint

Expand Down
6 changes: 3 additions & 3 deletions docs/oasis-node/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ oasis_storage_failures | Counter | Number of storage failures. | call | [storage
oasis_storage_latency | Summary | Storage call latency (seconds). | call | [storage/api](https://github.com/oasisprotocol/oasis-core/tree/master/go/storage/api/metrics.go)
oasis_storage_successes | Counter | Number of storage successes. | call | [storage/api](https://github.com/oasisprotocol/oasis-core/tree/master/go/storage/api/metrics.go)
oasis_storage_value_size | Summary | Storage call value size (bytes). | call | [storage/api](https://github.com/oasisprotocol/oasis-core/tree/master/go/storage/api/metrics.go)
oasis_tee_attestations_failed | Counter | Number of failed TEE attestations. | runtime | [runtime/host/sgx](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/metrics.go)
oasis_tee_attestations_performed | Counter | Number of TEE attestations performed. | runtime | [runtime/host/sgx](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/metrics.go)
oasis_tee_attestations_successful | Counter | Number of successful TEE attestations. | runtime | [runtime/host/sgx](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/metrics.go)
oasis_tee_attestations_failed | Counter | Number of failed TEE attestations. | runtime, kind | [runtime/host/sgx/common](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/common/metrics.go)
oasis_tee_attestations_performed | Counter | Number of TEE attestations performed. | runtime, kind | [runtime/host/sgx/common](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/common/metrics.go)
oasis_tee_attestations_successful | Counter | Number of successful TEE attestations. | runtime, kind | [runtime/host/sgx/common](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/host/sgx/common/metrics.go)
oasis_txpool_accepted_transactions | Counter | Number of accepted transactions (passing check tx). | runtime | [runtime/txpool](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/txpool/metrics.go)
oasis_txpool_local_queue_size | Gauge | Size of the local transactions schedulable queue (number of entries). | runtime | [runtime/txpool](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/txpool/metrics.go)
oasis_txpool_pending_check_size | Gauge | Size of the pending to be checked queue (number of entries). | runtime | [runtime/txpool](https://github.com/oasisprotocol/oasis-core/tree/master/go/runtime/txpool/metrics.go)
Expand Down
1 change: 1 addition & 0 deletions go/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ linters-settings:
- github.com/stretchr
- github.com/tidwall/btree
- github.com/tyler-smith/go-bip39
- github.com/mdlayher/vsock

linters:
disable-all: true
Expand Down
10 changes: 10 additions & 0 deletions go/common/crypto/hash/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding/hex"
"errors"
"hash"
"io"

cmtbytes "github.com/cometbft/cometbft/libs/bytes"

Expand Down Expand Up @@ -149,6 +150,15 @@ func NewFromBytes(data ...[]byte) (h Hash) {
return
}

// NewFromReader creates a new hash by hashing data from the provided reader until EOF.
func NewFromReader(reader io.Reader) (Hash, error) {
b := NewBuilder()
if _, err := io.Copy(b, reader); err != nil {
return Hash{}, err
}
return b.Build(), nil
}

// LoadFromHexBytes creates a new hash by loading it from the given CometBFT
// HexBytes byte array.
func LoadFromHexBytes(data cmtbytes.HexBytes) (h Hash) {
Expand Down
19 changes: 2 additions & 17 deletions go/common/sgx/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,25 +83,10 @@ func (m *MrEnclave) UnmarshalHex(text string) error {
// FromSgxs derives a MrEnclave from r, under the assumption that r will
// provide the entire `.sgxs` file.
func (m *MrEnclave) FromSgxs(r io.Reader) error {
// A `.sgxs` file's SHA256 digest is conveniently the MRENCLAVE.
var buf [32768]byte

h := sha256.New()
readLoop:
for {
l, err := r.Read(buf[:])
if l > 0 {
_, _ = h.Write(buf[:l])
}
switch err {
case nil:
case io.EOF:
break readLoop
default:
return fmt.Errorf("sgx: failed to read .sgxs: %w", err)
}
if _, err := io.Copy(h, r); err != nil {
return fmt.Errorf("sgx: failed to read sgxs: %w", err)
}

sum := h.Sum(nil)
return m.UnmarshalBinary(sum)
}
Expand Down
25 changes: 12 additions & 13 deletions go/runtime/host/sgx/tcb_cache.go → go/common/sgx/pcs/cache.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sgx
package pcs

import (
"bytes"
Expand All @@ -8,7 +8,6 @@ import (

"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/persistent"
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
)

const (
Expand All @@ -18,23 +17,23 @@ const (
tcbCacheSlowRefreshInterval = 24 * time.Hour
)

func readBundleMinTimestamp(bundle *pcs.TCBBundle) (time.Time, error) {
func readBundleMinTimestamp(bundle *TCBBundle) (time.Time, error) {
var err error
var info pcs.TCBInfo
var info TCBInfo
if err = json.Unmarshal(bundle.TCBInfo.TCBInfo, &info); err != nil {
return time.Time{}, fmt.Errorf("could not unmarshal TCB bundle info: %w", err)
}
var bundleUpdate time.Time
if bundleUpdate, err = time.Parse(pcs.TimestampFormat, info.NextUpdate); err != nil {
if bundleUpdate, err = time.Parse(TimestampFormat, info.NextUpdate); err != nil {
return time.Time{}, fmt.Errorf("unreadable TCB bundle info next update timestamp: %w", err)
}

var identity pcs.QEIdentity
var identity QEIdentity
if err = json.Unmarshal(bundle.QEIdentity.EnclaveIdentity, &identity); err != nil {
return time.Time{}, fmt.Errorf("could not unmarshal TCB bundle QE identity: %w", err)
}
var identityUpdate time.Time
if identityUpdate, err = time.Parse(pcs.TimestampFormat, identity.NextUpdate); err != nil {
if identityUpdate, err = time.Parse(TimestampFormat, identity.NextUpdate); err != nil {
return time.Time{}, fmt.Errorf("unreadable TCB bundle QE identity next update timestamp: %w", err)
}

Expand All @@ -45,10 +44,10 @@ func readBundleMinTimestamp(bundle *pcs.TCBBundle) (time.Time, error) {
}

type tcbBundleCache struct {
Bundle *pcs.TCBBundle `json:"bundle"`
FMSPC []byte `json:"fmspc"`
ExpectedExpiry time.Time `json:"expected_expiry"`
LastUpdate time.Time `json:"last_update"`
Bundle *TCBBundle `json:"bundle"`
FMSPC []byte `json:"fmspc"`
ExpectedExpiry time.Time `json:"expected_expiry"`
LastUpdate time.Time `json:"last_update"`
}

type tcbCache struct {
Expand All @@ -57,7 +56,7 @@ type tcbCache struct {
now func() time.Time
}

func (tc *tcbCache) check(fmspc []byte) (*pcs.TCBBundle, bool) {
func (tc *tcbCache) check(fmspc []byte) (*TCBBundle, bool) {
var err error

// Check if we have a copy in the local store.
Expand Down Expand Up @@ -98,7 +97,7 @@ func (tc *tcbCache) check(fmspc []byte) (*pcs.TCBBundle, bool) {
return stored.Bundle, refresh
}

func (tc *tcbCache) cache(tcbBundle *pcs.TCBBundle, fmspc []byte) {
func (tc *tcbCache) cache(tcbBundle *TCBBundle, fmspc []byte) {
expectedExpiry, err := readBundleMinTimestamp(tcbBundle)
if err != nil {
tc.logger.Error("could not determine next update timestamp from TCB bundle",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sgx
package pcs

import (
"encoding/json"
Expand All @@ -10,7 +10,6 @@ import (

"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/persistent"
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
)

const loggerModule = "runtime/host/sgx/tests"
Expand All @@ -23,7 +22,7 @@ func (ft *fakeTime) get() time.Time {
return ft.now
}

func testStorageRoundtrip(t *testing.T, store *persistent.ServiceStore, bundle *pcs.TCBBundle) {
func testStorageRoundtrip(t *testing.T, store *persistent.ServiceStore, bundle *TCBBundle) {
require := require.New(t)
fmspc := []byte("fmspc")

Expand All @@ -34,7 +33,7 @@ func testStorageRoundtrip(t *testing.T, store *persistent.ServiceStore, bundle *
require.EqualValues(cached, bundle, "tcbCache.check")
}

func testFMSPCInvalidation(t *testing.T, store *persistent.ServiceStore, bundle *pcs.TCBBundle) {
func testFMSPCInvalidation(t *testing.T, store *persistent.ServiceStore, bundle *TCBBundle) {
require := require.New(t)
fmspc := []byte("fmspc")
expiryTime, err := readBundleMinTimestamp(bundle)
Expand All @@ -44,7 +43,7 @@ func testFMSPCInvalidation(t *testing.T, store *persistent.ServiceStore, bundle
}
tcbCache := newMockTcbCache(store, logging.GetLogger(loggerModule), ft.get)

var cached *pcs.TCBBundle
var cached *TCBBundle
var refresh bool

// Cache initial and check.
Expand All @@ -64,7 +63,7 @@ func testFMSPCInvalidation(t *testing.T, store *persistent.ServiceStore, bundle
require.False(refresh, "tcbCache.check 3")
}

func testCheckIntervals(t *testing.T, store *persistent.ServiceStore, bundle *pcs.TCBBundle) {
func testCheckIntervals(t *testing.T, store *persistent.ServiceStore, bundle *TCBBundle) {
require := require.New(t)
fmspc := []byte("fmspc")
expiryTime, err := readBundleMinTimestamp(bundle)
Expand Down Expand Up @@ -149,21 +148,21 @@ func TestTCBCache(t *testing.T) {
rawQEIdentity, err := os.ReadFile("testdata/qe_identity_v2.json") // From PCS V4 response.
require.NoError(err, "Read test vector")

var tcbInfo pcs.SignedTCBInfo
var tcbInfo SignedTCBInfo
err = json.Unmarshal(rawTCBInfo, &tcbInfo)
require.NoError(err, "Parse TCB info")

var qeIdentity pcs.SignedQEIdentity
var qeIdentity SignedQEIdentity
err = json.Unmarshal(rawQEIdentity, &qeIdentity)
require.NoError(err, "Parse QE identity")

tcbBundle := pcs.TCBBundle{
tcbBundle := TCBBundle{
TCBInfo: tcbInfo,
QEIdentity: qeIdentity,
Certificates: rawCerts,
}

for name, fun := range map[string]func(*testing.T, *persistent.ServiceStore, *pcs.TCBBundle){
for name, fun := range map[string]func(*testing.T, *persistent.ServiceStore, *TCBBundle){
"StorageRoundtrip": testStorageRoundtrip,
"CheckIntervals": testCheckIntervals,
"FMSPCInvalidation": testFMSPCInvalidation,
Expand Down
30 changes: 23 additions & 7 deletions go/common/sgx/pcs/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import (
const (
pcsAPISubscriptionKeyHeader = "Ocp-Apim-Subscription-Key"
pcsAPITimeout = 10 * time.Second
pcsAPIBaseURL = "https://api.trustedservices.intel.com/sgx"
pcsAPIGetPCKCertificatePath = "/certification/v4/pckcert"
pcsAPIGetRevocationListPath = "/certification/v4/pckcrl"
pcsAPIGetTCBInfoPath = "/certification/v4/tcb"
pcsAPIGetQEIdentityPath = "/certification/v4/qe/identity"
pcsAPIBaseURL = "https://api.trustedservices.intel.com"
pcsAPIGetPCKCertificatePath = "/sgx/certification/v4/pckcert"
pcsAPIGetRevocationListPath = "/sgx/certification/v4/pckcrl"
pcsAPIGetSgxTCBInfoPath = "/sgx/certification/v4/tcb"
pcsAPIGetTdxTCBInfoPath = "/tdx/certification/v4/tcb"
pcsAPIGetSgxQEIdentityPath = "/sgx/certification/v4/qe/identity"
pcsAPIGetTdxQEIdentityPath = "/tdx/certification/v4/qe/identity"
pcsAPICertChainHeader = "TCB-Info-Issuer-Chain"
pcsAPIPCKIIssuerChainHeader = "SGX-PCK-Certificate-Issuer-Chain"
)
Expand Down Expand Up @@ -88,8 +90,22 @@ func (hc *httpClient) getUrl(p string) *url.URL { // nolint: revive
return &u
}

func (hc *httpClient) GetTCBBundle(ctx context.Context, fmspc []byte, update UpdateType) (*TCBBundle, error) {
var tcbBundle TCBBundle
func (hc *httpClient) GetTCBBundle(ctx context.Context, teeType TeeType, fmspc []byte, update UpdateType) (*TCBBundle, error) {
var (
tcbBundle TCBBundle
pcsAPIGetTCBInfoPath string
pcsAPIGetQEIdentityPath string
)
switch teeType {
case TeeTypeSGX:
pcsAPIGetTCBInfoPath = pcsAPIGetSgxTCBInfoPath
pcsAPIGetQEIdentityPath = pcsAPIGetSgxQEIdentityPath
case TeeTypeTDX:
pcsAPIGetTCBInfoPath = pcsAPIGetTdxTCBInfoPath
pcsAPIGetQEIdentityPath = pcsAPIGetTdxQEIdentityPath
default:
return nil, fmt.Errorf("pcs: unsupported TEE type: %s", teeType)
}

// First fetch TCB info.
u := hc.getUrl(pcsAPIGetTCBInfoPath)
Expand Down
2 changes: 1 addition & 1 deletion go/common/sgx/pcs/pcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
// Client is an Intel SGX PCS client interface.
type Client interface {
// GetTCBBundle retrieves the signed TCB artifacts needed to verify a quote.
GetTCBBundle(ctx context.Context, fmspc []byte, update UpdateType) (*TCBBundle, error)
GetTCBBundle(ctx context.Context, teeType TeeType, fmspc []byte, update UpdateType) (*TCBBundle, error)

// GetPCKCertificateChain retrieves the PCK certificate chain for the given platform data or PPID.
//
Expand Down
Loading

0 comments on commit 456a688

Please sign in to comment.