Skip to content

Commit 8ca2ad2

Browse files
committed
go/common/sgx/pcs/policy: Ensure FMSPC whitelist is empty
Ensure the FMSPC whitelist in the quote policy remains empty until the next feature version is enabled. Once that feature is enabled, these changes can be removed.
1 parent 9ab9e08 commit 8ca2ad2

File tree

24 files changed

+173
-47
lines changed

24 files changed

+173
-47
lines changed

go/common/node/node.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ func HashRAK(rak signature.PublicKey) hash.Hash {
574574
}
575575

576576
// Verify verifies the node's TEE capabilities, at the provided timestamp and height.
577-
func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64, constraints []byte, nodeID signature.PublicKey) error {
577+
func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64, constraints []byte, nodeID signature.PublicKey, isFeatureVersion242 bool) error {
578578
switch c.Hardware {
579579
case TEEHardwareIntelSGX:
580580
// Parse SGX remote attestation.
@@ -591,7 +591,7 @@ func (c *CapabilityTEE) Verify(teeCfg *TEEFeatures, ts time.Time, height uint64,
591591
if err := cbor.Unmarshal(constraints, &sc); err != nil {
592592
return fmt.Errorf("node: malformed SGX constraints: %w", err)
593593
}
594-
if err := sc.ValidateBasic(teeCfg); err != nil {
594+
if err := sc.ValidateBasic(teeCfg, isFeatureVersion242); err != nil {
595595
return fmt.Errorf("node: malformed SGX constraints: %w", err)
596596
}
597597

go/common/node/sgx.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func (sc *SGXConstraints) MarshalCBOR() ([]byte, error) {
9797
}
9898

9999
// ValidateBasic performs basic structure validity checks.
100-
func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures) error {
100+
func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures, isFeatureVersion242 bool) error {
101101
if cfg == nil {
102102
cfg = &emptyFeatures
103103
}
@@ -116,6 +116,13 @@ func (sc *SGXConstraints) ValidateBasic(cfg *TEEFeatures) error {
116116
return fmt.Errorf("TDX policy not supported")
117117
}
118118

119+
// Check that policy is compliant with the current feature version.
120+
if sc.Policy != nil {
121+
if err := sc.Policy.Validate(isFeatureVersion242); err != nil {
122+
return fmt.Errorf("invalid policy: %w", err)
123+
}
124+
}
125+
119126
return nil
120127
}
121128

go/common/node/sgx_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestSGXConstraintsV0(t *testing.T) {
2727
err = cbor.Unmarshal(raw, &sc)
2828
require.NoError(err, "Decode V0 SGX constraints")
2929

30-
err = sc.ValidateBasic(nil)
30+
err = sc.ValidateBasic(nil, true)
3131
require.NoError(err, "ValidateBasic V0 SGX constraints")
3232

3333
enc := cbor.Marshal(sc)
@@ -60,11 +60,11 @@ func TestSGXConstraintsV1(t *testing.T) {
6060
},
6161
},
6262
}
63-
err = sc.ValidateBasic(nil)
63+
err = sc.ValidateBasic(nil, true)
6464
require.Error(err, "ValidateBasic V1 SGX constraints without PCS support")
65-
err = sc.ValidateBasic(&TEEFeatures{})
65+
err = sc.ValidateBasic(&TEEFeatures{}, true)
6666
require.Error(err, "ValidateBasic V1 SGX constraints without PCS support")
67-
err = sc.ValidateBasic(&TEEFeatures{SGX: TEEFeaturesSGX{PCS: true}})
67+
err = sc.ValidateBasic(&TEEFeatures{SGX: TEEFeaturesSGX{PCS: true}}, true)
6868
require.NoError(err, "ValidateBasic V1 SGX constraints")
6969
}
7070

go/common/sgx/quote/quote.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,20 @@ type Policy struct {
6464
IAS *ias.QuotePolicy `json:"ias,omitempty" yaml:"ias,omitempty"`
6565
PCS *pcs.QuotePolicy `json:"pcs,omitempty" yaml:"pcs,omitempty"`
6666
}
67+
68+
// Validate validates the policy.
69+
func (p *Policy) Validate(isFeatureVersion242 bool) error {
70+
if isFeatureVersion242 {
71+
return nil
72+
}
73+
74+
if p.PCS == nil {
75+
return nil
76+
}
77+
78+
if len(p.PCS.FMSPCWhitelist) == 0 {
79+
return nil
80+
}
81+
82+
return fmt.Errorf("fmspc whitelist should be empty")
83+
}

go/consensus/cometbft/apps/keymanager/common/genesis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func RegistryRuntimes(ctx *tmapi.Context, doc *genesis.Document, epoch beacon.Ep
1616
regSt := doc.Registry
1717
rtMap := make(map[common.Namespace]*registry.Runtime)
1818
for _, rt := range regSt.Runtimes {
19-
err := registry.VerifyRuntime(&regSt.Parameters, ctx.Logger(), rt, true, false, epoch)
19+
err := registry.VerifyRuntime(&regSt.Parameters, ctx.Logger(), rt, true, false, epoch, true)
2020
if err != nil {
2121
ctx.Logger().Error("InitChain: Invalid runtime",
2222
"err", err,

go/consensus/cometbft/apps/keymanager/secrets/epoch.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import (
1010
tmapi "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/api"
1111
secretsState "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/apps/keymanager/secrets/state"
1212
registryState "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/apps/registry/state"
13+
"github.com/oasisprotocol/oasis-core/go/consensus/cometbft/features"
1314
"github.com/oasisprotocol/oasis-core/go/keymanager/secrets"
1415
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
16+
"github.com/oasisprotocol/oasis-core/go/upgrade/migrations"
1517
)
1618

1719
func (ext *secretsExt) onEpochChange(ctx *tmapi.Context, epoch beacon.EpochTime) error {
@@ -26,6 +28,11 @@ func (ext *secretsExt) onEpochChange(ctx *tmapi.Context, epoch beacon.EpochTime)
2628
return fmt.Errorf("failed to get consensus parameters: %w", err)
2729
}
2830

31+
isFeatureVersion242, err := features.IsFeatureVersion(ctx, migrations.Version242)
32+
if err != nil {
33+
return err
34+
}
35+
2936
// Recalculate all the key manager statuses.
3037
//
3138
// Note: This assumes that once a runtime is registered, it never expires.
@@ -64,7 +71,7 @@ func (ext *secretsExt) onEpochChange(ctx *tmapi.Context, epoch beacon.EpochTime)
6471
return fmt.Errorf("failed to query key manager master secret: %w", err)
6572
}
6673

67-
newStatus := generateStatus(ctx, rt, oldStatus, secret, nodes, params, epoch)
74+
newStatus := generateStatus(ctx, rt, oldStatus, secret, nodes, params, epoch, isFeatureVersion242)
6875
if forceEmit || !bytes.Equal(cbor.Marshal(oldStatus), cbor.Marshal(newStatus)) {
6976
ctx.Logger().Debug("status updated",
7077
"id", newStatus.ID,

go/consensus/cometbft/apps/keymanager/secrets/status.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func generateStatus( // nolint: gocyclo
3232
nodes []*node.Node,
3333
params *registry.ConsensusParameters,
3434
epoch beacon.EpochTime,
35+
isFeatureVersion242 bool,
3536
) *secrets.Status {
3637
status := &secrets.Status{
3738
ID: kmrt.ID,
@@ -111,7 +112,7 @@ nextNode:
111112
continue nextNode
112113
}
113114

114-
initResponse, err := VerifyExtraInfo(ctx.Logger(), n.ID, kmrt, nodeRt, ts, height, params)
115+
initResponse, err := VerifyExtraInfo(ctx.Logger(), n.ID, kmrt, nodeRt, ts, height, params, isFeatureVersion242)
115116
if err != nil {
116117
ctx.Logger().Error("failed to validate ExtraInfo", append(vars, "err", err)...)
117118
continue nextNode
@@ -231,8 +232,9 @@ func VerifyExtraInfo(
231232
ts time.Time,
232233
height uint64,
233234
params *registry.ConsensusParameters,
235+
isFeatureVersion242 bool,
234236
) (*secrets.InitResponse, error) {
235-
if err := registry.VerifyNodeRuntimeEnclaveIDs(logger, nodeID, nodeRt, rt, params.TEEFeatures, ts, height); err != nil {
237+
if err := registry.VerifyNodeRuntimeEnclaveIDs(logger, nodeID, nodeRt, rt, params.TEEFeatures, ts, height, isFeatureVersion242); err != nil {
236238
return nil, err
237239
}
238240
if nodeRt.ExtraInfo == nil {

go/consensus/cometbft/apps/keymanager/secrets/status_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ func TestGenerateStatus(t *testing.T) {
207207
t.Run("No nodes", func(t *testing.T) {
208208
require := require.New(t)
209209

210-
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes[0:6], params, epoch)
210+
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes[0:6], params, epoch, true)
211211
require.Equal(uninitializedStatus, newStatus, "key manager committee should be empty")
212212

213-
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes[0:6], params, epoch)
213+
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes[0:6], params, epoch, true)
214214
require.Equal(initializedStatus, newStatus, "key manager committee should be empty")
215215
})
216216

@@ -225,16 +225,16 @@ func TestGenerateStatus(t *testing.T) {
225225
Policy: &policy,
226226
Nodes: []signature.PublicKey{nodes[6].ID},
227227
}
228-
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes[6:7], params, epoch)
228+
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes[6:7], params, epoch, true)
229229
require.Equal(expStatus, newStatus, "node 6 should form the committee if key manager not initialized")
230230

231-
newStatus = generateStatus(ctx, runtimes[0], expStatus, nil, nodes[6:7], params, epoch)
231+
newStatus = generateStatus(ctx, runtimes[0], expStatus, nil, nodes[6:7], params, epoch, true)
232232
require.Equal(expStatus, newStatus, "node 6 should form the committee if key manager is not secure")
233233

234234
expStatus.IsSecure = true
235235
expStatus.Checksum = checksum
236236
expStatus.Nodes = nil
237-
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes[6:7], params, epoch)
237+
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes[6:7], params, epoch, true)
238238
require.Equal(expStatus, newStatus, "node 6 should not be added to the committee if key manager is secure or checksum differs")
239239
})
240240

@@ -251,20 +251,20 @@ func TestGenerateStatus(t *testing.T) {
251251
Policy: &policy,
252252
Nodes: []signature.PublicKey{nodes[6].ID},
253253
}
254-
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes, params, epoch)
254+
newStatus := generateStatus(ctx, runtimes[0], uninitializedStatus, nil, nodes, params, epoch, true)
255255
require.Equal(expStatus, newStatus, "node 6 should be the source of truth and form the committee")
256256

257257
// If the order is reversed, it should be the other way around.
258258
expStatus.IsSecure = true
259259
expStatus.Nodes = []signature.PublicKey{nodes[7].ID}
260-
newStatus = generateStatus(ctx, runtimes[0], uninitializedStatus, nil, reverse(nodes), params, epoch)
260+
newStatus = generateStatus(ctx, runtimes[0], uninitializedStatus, nil, reverse(nodes), params, epoch, true)
261261
require.Equal(expStatus, newStatus, "node 7 should be the source of truth and form the committee")
262262

263263
// If the key manager is already initialized as secure with a checksum, then all nodes
264264
// except 8 and 9 are ignored.
265265
expStatus.Checksum = checksum
266266
expStatus.Nodes = []signature.PublicKey{nodes[8].ID, nodes[9].ID}
267-
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes, params, epoch)
267+
newStatus = generateStatus(ctx, runtimes[0], initializedStatus, nil, nodes, params, epoch, true)
268268
require.Equal(expStatus, newStatus, "node 7 and 8 should form the committee if key manager is initialized as secure")
269269

270270
// The second key manager.
@@ -277,7 +277,7 @@ func TestGenerateStatus(t *testing.T) {
277277
Nodes: []signature.PublicKey{nodes[4].ID, nodes[9].ID},
278278
}
279279
initializedStatus.ID = runtimeIDs[1]
280-
newStatus = generateStatus(ctx, runtimes[1], initializedStatus, nil, nodes, params, epoch)
280+
newStatus = generateStatus(ctx, runtimes[1], initializedStatus, nil, nodes, params, epoch, true)
281281
require.Equal(expStatus, newStatus, "node 4 and 9 should form the committee")
282282
})
283283
}

go/consensus/cometbft/apps/keymanager/secrets/txs.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ func (ext *secretsExt) updatePolicy(
7676
status.NextPolicy = sigPol
7777

7878
// Support legacy behavior where the policy was applied immediately.
79-
ok, err := features.IsFeatureVersion(ctx, migrations.Version242)
79+
isFeatureVersion242, err := features.IsFeatureVersion(ctx, migrations.Version242)
8080
if err != nil {
8181
return err
8282
}
83-
if !ok {
83+
if !isFeatureVersion242 {
8484
// Ok, as far as we can tell the new policy is valid, apply it.
8585
//
8686
// Note: The key manager cohort responsible for servicing this ID
@@ -104,7 +104,7 @@ func (ext *secretsExt) updatePolicy(
104104

105105
nodes, _ := regState.Nodes(ctx)
106106
registry.SortNodeList(nodes)
107-
status = generateStatus(ctx, kmRt, status, nil, nodes, regParams, epoch)
107+
status = generateStatus(ctx, kmRt, status, nil, nodes, regParams, epoch, isFeatureVersion242)
108108
}
109109

110110
if err := state.SetStatus(ctx, status); err != nil {

go/consensus/cometbft/apps/registry/genesis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (app *Application) InitChain(ctx *abciAPI.Context, _ types.RequestInitChain
5555
if rt == nil {
5656
return fmt.Errorf("registry: genesis runtime index %d is nil", i)
5757
}
58-
err := registry.VerifyRuntime(&st.Parameters, ctx.Logger(), rt, ctx.IsInitChain(), false, epoch)
58+
err := registry.VerifyRuntime(&st.Parameters, ctx.Logger(), rt, ctx.IsInitChain(), false, epoch, true)
5959
if err != nil {
6060
return err
6161
}

0 commit comments

Comments
 (0)