Skip to content

Commit

Permalink
keymanager/src/client: Fetch public keys using insecure RPC requests
Browse files Browse the repository at this point in the history
  • Loading branch information
peternose committed Dec 16, 2022
1 parent 85dfb6f commit 89139ec
Show file tree
Hide file tree
Showing 16 changed files with 645 additions and 87 deletions.
22 changes: 20 additions & 2 deletions go/runtime/host/protocol/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ type Body struct {
RuntimeKeyManagerPolicyUpdateResponse *Empty `json:",omitempty"`
RuntimeKeyManagerQuotePolicyUpdateRequest *RuntimeKeyManagerQuotePolicyUpdateRequest `json:",omitempty"`
RuntimeKeyManagerQuotePolicyUpdateResponse *Empty `json:",omitempty"`
RuntimeKeyManagerRakUpdateRequest *RuntimeKeyManagerRakUpdateRequest `json:",omitempty"`
RuntimeKeyManagerRakUpdateResponse *Empty `json:",omitempty"`
RuntimeQueryRequest *RuntimeQueryRequest `json:",omitempty"`
RuntimeQueryResponse *RuntimeQueryResponse `json:",omitempty"`
RuntimeConsensusSyncRequest *RuntimeConsensusSyncRequest `json:",omitempty"`
Expand Down Expand Up @@ -174,6 +176,9 @@ type Features struct {
// KeyManagerQuotePolicyUpdates is a feature specifying that the runtime supports updating
// key manager's quote policy.
KeyManagerQuotePolicyUpdates bool `json:"key_manager_quote_policy_updates,omitempty"`
// KeyManagerRakUpdates is a feature specifying that the runtime supports updating
// key manager's RAK.
KeyManagerRakUpdates bool `json:"key_manager_rak_updates,omitempty"`
}

// HasScheduleControl returns true when the runtime supports the schedule control feature.
Expand Down Expand Up @@ -402,17 +407,30 @@ type RuntimeExecuteTxBatchResponse struct {
Deprecated1 cbor.RawMessage `json:"batch_weight_limits,omitempty"`
}

// RuntimeKeyManagerPolicyUpdateRequest is a runtime key manager policy request message body.
// RuntimeKeyManagerPolicyUpdateRequest is a runtime key manager policy update request message body.
type RuntimeKeyManagerPolicyUpdateRequest struct {
SignedPolicyRaw []byte `json:"signed_policy_raw"`
}

// RuntimeKeyManagerQuotePolicyUpdateRequest is a runtime key manager quote policy request
// RuntimeKeyManagerQuotePolicyUpdateRequest is a runtime key manager quote policy update request
// message body.
type RuntimeKeyManagerQuotePolicyUpdateRequest struct {
Policy quote.Policy `json:"policy"`
}

// RAKBinding binds the remote attestation's public key to a remote attestation quote.
type RAKBinding struct {
// RAK is remote attestation's public key.
RAK signature.PublicKey `json:"rak_pub"`
// Quote is remote attestation quote.
Quote quote.Quote `json:"quote"`
}

// RuntimeKeyManagerRakUpdateRequest is a runtime key manager RAK update request message body.
type RuntimeKeyManagerRakUpdateRequest struct {
RakBindings []RAKBinding `json:"rak_bindings"`
}

// RuntimeQueryRequest is a runtime query request message body.
type RuntimeQueryRequest struct {
// ConsensusBlock is the consensus light block at the last finalized round
Expand Down
6 changes: 6 additions & 0 deletions go/runtime/host/sgx/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/node"
"github.com/oasisprotocol/oasis-core/go/common/sgx/aesm"
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
Expand Down Expand Up @@ -72,6 +73,11 @@ func (ec *teeStateECDSA) Update(ctx context.Context, sp *sgxProvisioner, conn pr
return nil, fmt.Errorf("failed to get quote: %w", err)
}

logger := logging.GetLogger("quote-logger")
logger.Info("new quote",
"quote", rawQuote,
)

var quote pcs.Quote
if err = quote.UnmarshalBinary(rawQuote); err != nil {
return nil, fmt.Errorf("failed to parse quote: %w", err)
Expand Down
168 changes: 153 additions & 15 deletions go/runtime/registry/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ import (

"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/identity"
"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/node"
"github.com/oasisprotocol/oasis-core/go/common/sgx/quote"
"github.com/oasisprotocol/oasis-core/go/common/version"
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
consensusResults "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction/results"
"github.com/oasisprotocol/oasis-core/go/keymanager/api"
keymanager "github.com/oasisprotocol/oasis-core/go/keymanager/api"
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
"github.com/oasisprotocol/oasis-core/go/runtime/host"
"github.com/oasisprotocol/oasis-core/go/runtime/host/multi"
"github.com/oasisprotocol/oasis-core/go/runtime/host/protocol"
runtimeKeymanager "github.com/oasisprotocol/oasis-core/go/runtime/keymanager/api"
"github.com/oasisprotocol/oasis-core/go/runtime/nodes"
"github.com/oasisprotocol/oasis-core/go/runtime/txpool"
storage "github.com/oasisprotocol/oasis-core/go/storage/api"
"github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer"
Expand Down Expand Up @@ -446,7 +449,7 @@ type runtimeHostNotifier struct {
logger *logging.Logger
}

func (n *runtimeHostNotifier) watchPolicyUpdates() {
func (n *runtimeHostNotifier) watchPolicyAndRakUpdates() {
// Subscribe to runtime descriptor updates.
dscCh, dscSub, err := n.runtime.WatchRegistryDescriptor()
if err != nil {
Expand Down Expand Up @@ -474,7 +477,7 @@ func (n *runtimeHostNotifier) watchPolicyUpdates() {
wg.Add(1)
go func(kmRtID *common.Namespace) {
defer wg.Done()
n.watchKmPolicyUpdates(ctx, kmRtID)
n.watchKmPolicyAndRakUpdates(ctx, kmRtID)
}(kmRtID)

// Restart the updater if the runtime changes the key manager. This should happen
Expand Down Expand Up @@ -506,7 +509,7 @@ func (n *runtimeHostNotifier) watchPolicyUpdates() {
}
}

func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *common.Namespace) {
func (n *runtimeHostNotifier) watchKmPolicyAndRakUpdates(ctx context.Context, kmRtID *common.Namespace) {
// No need to watch anything if key manager is not set.
if kmRtID == nil {
return
Expand Down Expand Up @@ -538,19 +541,38 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *
}
defer evSub.Close()

// Fetch runtime info so that we know which features the runtime supports.
rtInfo, err := n.host.GetInfo(ctx)
// Subscribe to node events (RAK or quote might change).
nodesCh, nodesSub, err := n.consensus.Registry().WatchNodeList(ctx)
if err != nil {
n.logger.Error("failed to fetch runtime info",
n.logger.Error("failed to watch node list",
"err", err,
)
return
}
defer nodesSub.Close()

watcher, err := nodes.NewVersionedNodeDescriptorWatcher(ctx, n.consensus)
if err != nil {
n.logger.Error("failed to create node desc watcher",
"err", err,
)
return
}

watcherCh, watcherSub, err := watcher.WatchNodeUpdates()
if err != nil {
n.logger.Error("failed to watch node updates",
"err", err,
)
return
}
defer watcherSub.Close()

var (
st *keymanager.Status
sc *node.SGXConstraints
vi *registry.VersionInfo
st *keymanager.Status
sc *node.SGXConstraints
vi *registry.VersionInfo
kms map[signature.PublicKey]struct{}
)

for {
Expand All @@ -566,11 +588,6 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *

n.updateKeyManagerPolicy(ctx, st.Policy)
case epoch := <-epoCh:
// Skip quote policy updates if the runtime doesn't support them.
if !rtInfo.Features.KeyManagerQuotePolicyUpdates {
continue
}

// Check if the key manager was redeployed, as that is when a new quote policy might
// take effect.
dsc, err := n.consensus.Registry().GetRuntime(ctx, &registry.GetRuntimeQuery{
Expand Down Expand Up @@ -607,6 +624,40 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *
sc = &newSc

n.updateKeyManagerQuotePolicy(ctx, sc.Policy)
case nodeList := <-nodesCh:
watcher.Reset()

kms = make(map[signature.PublicKey]struct{})
for _, n := range nodeList.Nodes {
if !n.HasRoles(node.RoleKeyManager) {
continue
}
for _, rt := range n.Runtimes {
if rt.ID.Equal(kmRtID) {
kms[n.ID] = struct{}{}
break
}
}
}

for id := range kms {
if _, err := watcher.WatchNode(ctx, id); err != nil {
n.logger.Error("failed to watch node",
"err", err,
"id", id,
)
}
}

n.updateKeyManagerRak(ctx, kmRtID, kms, watcher)
case watcherEv := <-watcherCh:
if watcherEv.Update == nil {
continue
}
if _, ok := kms[watcherEv.Update.ID]; !ok {
continue
}
n.updateKeyManagerRak(ctx, kmRtID, kms, watcher)
case ev := <-evCh:
// Runtime host changes, make sure to update the policies if runtime is restarted.
if ev.Started == nil && ev.Updated == nil {
Expand All @@ -619,6 +670,7 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *
if sc != nil {
n.updateKeyManagerQuotePolicy(ctx, sc.Policy)
}
n.updateKeyManagerRak(ctx, kmRtID, kms, watcher)
}
}
}
Expand All @@ -645,6 +697,18 @@ func (n *runtimeHostNotifier) updateKeyManagerPolicy(ctx context.Context, policy
}

func (n *runtimeHostNotifier) updateKeyManagerQuotePolicy(ctx context.Context, policy *quote.Policy) {
// Skip quote policy updates if the runtime doesn't support them.
rtInfo, err := n.host.GetInfo(ctx)
if err != nil {
n.logger.Error("failed to fetch runtime info",
"err", err,
)
return
}
if !rtInfo.Features.KeyManagerQuotePolicyUpdates {
return
}

n.logger.Debug("got key manager quote policy update", "policy", policy)

req := &protocol.Body{RuntimeKeyManagerQuotePolicyUpdateRequest: &protocol.RuntimeKeyManagerQuotePolicyUpdateRequest{
Expand All @@ -663,6 +727,80 @@ func (n *runtimeHostNotifier) updateKeyManagerQuotePolicy(ctx context.Context, p
n.logger.Debug("key manager quote policy update dispatched")
}

func (n *runtimeHostNotifier) updateKeyManagerRak(ctx context.Context, kmRtID *common.Namespace, kms map[signature.PublicKey]struct{}, watcher nodes.VersionedNodeDescriptorWatcher) {
// Skip RAK updates if the runtime doesn't support them.
rtInfo, err := n.host.GetInfo(ctx)
if err != nil {
n.logger.Error("failed to fetch runtime info",
"err", err,
)
return
}
if !rtInfo.Features.KeyManagerRakUpdates {
return
}

var bindings []protocol.RAKBinding

for id := range kms {
km := watcher.Lookup(id)
if km == nil {
continue
}

loop:
for _, rt := range km.Runtimes {
if !rt.ID.Equal(kmRtID) {
continue
}

tee := rt.Capabilities.TEE
if tee == nil {
break
}

var binding protocol.RAKBinding

switch tee.Hardware {
case node.TEEHardwareInvalid:
binding.RAK = api.TestPublicKey
case node.TEEHardwareIntelSGX:
var sa node.SGXAttestation
if err := cbor.Unmarshal(tee.Attestation, &sa); err != nil {
n.logger.Error("malformed SGX attestation",
"err", err,
)
break loop
}
binding.RAK = tee.RAK
binding.Quote = sa.Quote
default:
break loop
}

bindings = append(bindings, binding)
break
}
}

n.logger.Debug("got key manager RAK update", "bindings", bindings)

req := &protocol.Body{RuntimeKeyManagerRakUpdateRequest: &protocol.RuntimeKeyManagerRakUpdateRequest{
RakBindings: bindings,
}}

ctx, cancel := context.WithTimeout(ctx, notifyTimeout)
defer cancel()

if _, err := n.host.Call(ctx, req); err != nil {
n.logger.Error("failed dispatching key manager RAK update to runtime",
"err", err,
)
return
}
n.logger.Debug("key manager RAK update dispatched")
}

func (n *runtimeHostNotifier) watchConsensusLightBlocks() {
rawCh, sub, err := n.consensus.WatchBlocks(n.ctx)
if err != nil {
Expand Down Expand Up @@ -726,7 +864,7 @@ func (n *runtimeHostNotifier) Start() error {
}
n.started = true

go n.watchPolicyUpdates()
go n.watchPolicyAndRakUpdates()
go n.watchConsensusLightBlocks()

return nil
Expand Down
6 changes: 6 additions & 0 deletions keymanager/src/api/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ pub enum KeyManagerError {
PolicyInvalid(#[from] anyhow::Error),
#[error("policy has insufficient signatures")]
PolicyInsufficientSignatures,
#[error("quote policy missing")]
QuotePolicyMissing,
#[error("rak binding missing")]
RAKBindingMissing,
#[error("signature verification failed")]
SignatureVerificationFailed,
#[error(transparent)]
Other(anyhow::Error),
}
Loading

0 comments on commit 89139ec

Please sign in to comment.