/
keymanager_replicate.go
135 lines (117 loc) · 3.54 KB
/
keymanager_replicate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package runtime
import (
"bytes"
"context"
"fmt"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/version"
keymanager "github.com/oasisprotocol/oasis-core/go/keymanager/api"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/env"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/scenario"
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
)
// KeymanagerReplicate is the keymanager replication scenario.
var KeymanagerReplicate scenario.Scenario = newKmReplicateImpl()
type kmReplicateImpl struct {
runtimeImpl
}
func newKmReplicateImpl() scenario.Scenario {
return &kmReplicateImpl{
runtimeImpl: *newRuntimeImpl("keymanager-replication", BasicKVEncTestClient),
}
}
func (sc *kmReplicateImpl) Clone() scenario.Scenario {
return &kmReplicateImpl{
runtimeImpl: *sc.runtimeImpl.Clone().(*runtimeImpl),
}
}
func (sc *kmReplicateImpl) Fixture() (*oasis.NetworkFixture, error) {
f, err := sc.runtimeImpl.Fixture()
if err != nil {
return nil, err
}
// This requires multiple keymanagers.
f.Keymanagers = []oasis.KeymanagerFixture{
{Runtime: 0, Entity: 1},
{Runtime: 0, Entity: 1},
}
return f, nil
}
func (sc *kmReplicateImpl) Run(childEnv *env.Env) error {
ctx := context.Background()
if err := sc.startNetworkAndTestClient(ctx, childEnv); err != nil {
return err
}
// Wait for the client to exit.
if err := sc.waitTestClientOnly(); err != nil {
return err
}
// Open a control connection to the replica.
if kmLen := len(sc.Net.Keymanagers()); kmLen < 2 {
return fmt.Errorf("expected more than 1 keymanager, have: %v", kmLen)
}
replica := sc.Net.Keymanagers()[1]
ctrl, err := oasis.NewController(replica.SocketPath())
if err != nil {
return err
}
// Extract the replica's ExtraInfo.
node, err := ctrl.Registry.GetNode(
ctx,
®istry.IDQuery{
ID: replica.NodeID,
},
)
if err != nil {
return err
}
rt := node.GetRuntime(keymanagerID, version.Version{})
if rt == nil {
return fmt.Errorf("replica is missing keymanager runtime from descriptor")
}
var signedInitResponse keymanager.SignedInitResponse
if err = cbor.Unmarshal(rt.ExtraInfo, &signedInitResponse); err != nil {
return fmt.Errorf("failed to unmarshal replica extrainfo")
}
// Grab a state dump and cross check the checksum with that of
// the replica.
doc, err := ctrl.Consensus.StateToGenesis(ctx, 0)
if err != nil {
return fmt.Errorf("failed to obtain consensus state: %w", err)
}
if err = func() error {
for _, status := range doc.KeyManager.Statuses {
if !status.ID.Equal(&keymanagerID) {
continue
}
if !status.IsInitialized {
return fmt.Errorf("key manager failed to initialize")
}
if !bytes.Equal(status.Checksum, signedInitResponse.InitResponse.Checksum) {
return fmt.Errorf("key manager failed to replicate, checksum mismatch")
}
return nil
}
return fmt.Errorf("consensus state missing km status")
}(); err != nil {
return err
}
// Since the replica has published an ExtraInfo that shows that it has
// the correct master secret checksum, the replication process has
// succeeded from the enclave's point of view.
// Query the node's keymanager consensus endpoint.
status, err := ctrl.Keymanager.GetStatus(ctx, ®istry.NamespaceQuery{
ID: keymanagerID,
})
if err != nil {
return err
}
for _, v := range status.Nodes {
// And ensure that the node is present.
if v.Equal(replica.NodeID) {
return nil
}
}
return fmt.Errorf("node missing from km status")
}