Skip to content

Commit

Permalink
runtime: Add conditional SGX attestation parsing for rofl.Register txs
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrus committed Jan 13, 2025
1 parent 171ab2a commit 69a3b8a
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions .changelog/876.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
runtime: Add conditional SGX attestation parsing for rofl.Register txs
10 changes: 10 additions & 0 deletions storage/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,16 @@ func (c *StorageClient) RuntimeTransactions(ctx context.Context, p apiTypes.GetR
}
}

// Try extracting parsed PCS quote from rofl.Register transaction body.
if t.Method != nil && *t.Method == "rofl.Register" {
nb, err := extractPCSQuote(t.Body)
if err != nil {
c.logger.Warn("failed to extract PCS quote from rofl.Register transaction body", "tx_hash", t.Hash, "err", err)
// In case of errors, original body is returned.
}
t.Body = nb
}

ts.Transactions = append(ts.Transactions, t)
}

Expand Down
164 changes: 164 additions & 0 deletions storage/client/rofl_quotes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package client

import (
"encoding/json"
"fmt"
"reflect"
"unsafe"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/sgx"
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"

"github.com/oasisprotocol/nexus/coreapi/v24.0/common/node"
)

// This file contains custom serialization logic for `rofl.Register` transactions.
// It handles the parsing and enhanced processing of attestation data in rofl.Register transactions.
// The goal is to produce a structured representation of the attestation and embed it into the transaction body.

type Header struct {
Version uint16 `json:"version"`
TeeType pcs.TeeType `json:"tee_type"`
QEVendorID []byte `json:"qe_vendor_id"`
AttestationKeyType pcs.AttestationKeyType `json:"attestation_key_type"`
}

type EnclaveIdentity struct {
MrEnclave sgx.MrEnclave `json:"mr_enclave"`
MrSigner sgx.MrSigner `json:"mr_signer"`
}

type ReportBody struct {
ReportData []byte `json:"report_data"`
EnclaveIdentity EnclaveIdentity `json:"enclave_identity"`
}

// Quote is an enclave quote.
type EnclaveQuote struct {
Header Header `json:"header"`
ReportBody ReportBody `json:"report_body"`
Signature pcs.QuoteSignature `json:"signature"`
}

// Parsed version of <TODO LINK>.
type ParsedPSCQuoteBundle struct {
TCB pcs.TCBBundle `json:"tcb"`
Quote EnclaveQuote `json:"quote"`
}

// Matches: <TODO LINK>.
type ParsedPCSQuote struct {
PCS *ParsedPSCQuoteBundle `json:"pcs"`
}

// Matches: <TODO LINK> with updated Quote field.
type ParsedAttestation struct {
// Quote is the parsed quote.
Quote ParsedPCSQuote `json:"quote"`

// Height is the runtime's view of the consensus layer height at the time of attestation.
Height uint64 `json:"height"`

// Signature is the signature of the attestation by the enclave (RAK).
Signature signature.RawSignature `json:"signature"`
}

// Serialize the transaction body with enhanced attestation parsing for SGX hardware.
// If the CapabilityTEE's hardware type is SGX, attempts to parse the attestation field,
// replacing it with a structured SGXAttestation. If parsing fails or the hardware type
// is not SGX, the original transaction body is returned unchanged.
func extractPCSQuote(untyped *map[string]interface{}) (*map[string]interface{}, error) {
raw, err := json.Marshal(untyped)
if err != nil {
return untyped, fmt.Errorf("failed to marshal untyped body: %w", err)
}
var body rofl.Register
if err := json.Unmarshal(raw, &body); err != nil {
return untyped, fmt.Errorf("failed to unmarshal rofl.Register body: %w", err)
}

// If not SGX attestation, return original.
if uint8(body.EndorsedCapability.CapabilityTEE.Hardware) != uint8(node.TEEHardwareIntelSGX) {
return untyped, fmt.Errorf("not an SGX attestation")
}

// Try parsing the SGX Attestation.
var sa node.SGXAttestation
if err := cbor.Unmarshal(body.EndorsedCapability.CapabilityTEE.Attestation, &sa); err != nil {
return untyped, fmt.Errorf("failed to unmarshal SGX attestation: %w", err)
}

// Try parsing the PCS Quote. (We don't try parsing the IAS quote since it's deprecated, so we mostly care for PCS).
var pcsQuote pcs.Quote
if sa.Quote.PCS == nil {
return untyped, fmt.Errorf("missing PCS quote")
}
if err := pcsQuote.UnmarshalBinary(sa.Quote.PCS.Quote); err != nil {
return untyped, fmt.Errorf("failed to unmarshal PCS quote: %w", err)
}

// Pick ReportBody from the PCS quote (TODO: add method to oasis-core to expose this).
val := reflect.ValueOf(&pcsQuote).Elem()
field := val.FieldByName("reportBody")
if !field.IsValid() {
return untyped, fmt.Errorf("failed to extract PCS report body")
}
fieldValue := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
reportBody, ok := fieldValue.Interface().(pcs.ReportBody)
if !ok {
return untyped, fmt.Errorf("failed to extract PCS report body interface")
}

// Update the body with the parsed data.
parsedRegister := struct {
rofl.Register
// Override Attestation field.
EndorsedCapability struct {
CapabilityTEE struct {
node.CapabilityTEE
Attestation ParsedAttestation `json:"attestation"`
} `json:"capability_tee"`
NodeEndorsement signature.Signature `json:"node_endorsement"`
} `json:"ect"` //nolint: misspell
}{
Register: body,
}
parsedRegister.EndorsedCapability.CapabilityTEE.Attestation = ParsedAttestation{
Quote: ParsedPCSQuote{
PCS: &ParsedPSCQuoteBundle{
TCB: sa.Quote.PCS.TCB, // PCS is not null, otherwise we wouldn't have reached this point.
Quote: EnclaveQuote{
Header: Header{
Version: pcsQuote.Header().Version(),
TeeType: pcsQuote.Header().TeeType(),
QEVendorID: pcsQuote.Header().QEVendorID(),
AttestationKeyType: pcsQuote.Header().AttestationKeyType(),
},
ReportBody: ReportBody{
ReportData: reportBody.ReportData(),
EnclaveIdentity: EnclaveIdentity{
MrEnclave: reportBody.AsEnclaveIdentity().MrEnclave,
MrSigner: reportBody.AsEnclaveIdentity().MrSigner,
},
},
Signature: pcsQuote.Signature(),
},
},
},
Height: sa.Height,
Signature: sa.Signature,
}

raw, err = json.Marshal(parsedRegister)
if err != nil {
return untyped, fmt.Errorf("failed to marshal parsed body: %w", err)
}
var newrt *map[string]interface{}
if err := json.Unmarshal(raw, &newrt); err != nil {
return untyped, fmt.Errorf("failed to unmarshal parsed body: %w", err)
}
return newrt, nil
}

0 comments on commit 69a3b8a

Please sign in to comment.