From c8c37354de4a3d892ff268cb5e8e83959e60e53d Mon Sep 17 00:00:00 2001 From: Jernej Kos Date: Fri, 24 Jan 2025 16:20:44 +0100 Subject: [PATCH] feat(cmd/rofl): Add --verify to build to verify enclave identities --- cmd/rofl/build/build.go | 82 ++++++++++++++++++++++++++++++++++++++++- cmd/rofl/mgmt.go | 4 ++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/cmd/rofl/build/build.go b/cmd/rofl/build/build.go index 83642d6..f4f520e 100644 --- a/cmd/rofl/build/build.go +++ b/cmd/rofl/build/build.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "maps" "os" "github.com/spf13/cobra" @@ -14,7 +15,9 @@ import ( "github.com/oasisprotocol/oasis-core/go/common/sgx" "github.com/oasisprotocol/oasis-core/go/common/version" "github.com/oasisprotocol/oasis-core/go/runtime/bundle" + "github.com/oasisprotocol/oasis-sdk/client-sdk/go/client" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/connection" + "github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl" buildRofl "github.com/oasisprotocol/cli/build/rofl" "github.com/oasisprotocol/cli/cmd/common" @@ -33,6 +36,7 @@ var ( buildMode string offline bool doUpdate bool + doVerify bool deploymentName string Cmd = &cobra.Command{ @@ -44,6 +48,10 @@ var ( npa := common.GetNPASelection(cfg) manifest, deployment := roflCommon.LoadManifestAndSetNPA(cfg, npa, deploymentName, true) + if doVerify && doUpdate { + cobra.CheckErr("only one of --verify and --update-manifest may be passed") + } + fmt.Println("Building a ROFL application...") fmt.Printf("Deployment: %s\n", deploymentName) fmt.Printf("Network: %s\n", deployment.Network) @@ -147,6 +155,70 @@ var ( runScript(manifest, buildRofl.ScriptBundlePost) + buildEnclaves := make(map[sgx.EnclaveIdentity]struct{}) + for _, eid := range eids { + buildEnclaves[*eid] = struct{}{} + } + + manifestEnclaves := make(map[sgx.EnclaveIdentity]struct{}) + for _, eid := range deployment.Policy.Enclaves { + manifestEnclaves[eid] = struct{}{} + } + + // Perform verification when requested. + if doVerify { + showIdentityDiff := func(build, other map[sgx.EnclaveIdentity]struct{}, otherName string) { + fmt.Println("Built enclave identities:") + for enclaveID := range build { + data, _ := enclaveID.MarshalText() + fmt.Printf(" - %s\n", string(data)) + } + + fmt.Printf("%s enclave identities:\n", otherName) + for enclaveID := range other { + data, _ := enclaveID.MarshalText() + fmt.Printf(" - %s\n", string(data)) + } + } + + if !maps.Equal(buildEnclaves, manifestEnclaves) { + fmt.Println("Built enclave identities DIFFER from manifest enclave identities!") + showIdentityDiff(buildEnclaves, manifestEnclaves, "Manifest") + cobra.CheckErr(fmt.Errorf("enclave identity verification failed")) + } + + fmt.Println("Built enclave identities MATCH manifest enclave identities.") + + // When not in offline mode, also verify on-chain enclave identities. + if !offline { + var conn connection.Connection + ctx := context.Background() + conn, err = connection.Connect(ctx, npa.Network) + cobra.CheckErr(err) + + var appID rofl.AppID + _ = appID.UnmarshalText([]byte(deployment.AppID)) // Already verified. + + var appCfg *rofl.AppConfig + appCfg, err = conn.Runtime(npa.ParaTime).ROFL.App(ctx, client.RoundLatest, appID) + cobra.CheckErr(err) + + cfgEnclaves := make(map[sgx.EnclaveIdentity]struct{}) + for _, eid := range appCfg.Policy.Enclaves { + cfgEnclaves[eid] = struct{}{} + } + + if !maps.Equal(manifestEnclaves, cfgEnclaves) { + fmt.Println("Built enclave identities DIFFER from on-chain enclave identities!") + showIdentityDiff(buildEnclaves, cfgEnclaves, "On-chain") + cobra.CheckErr(fmt.Errorf("enclave identity verification failed")) + } + + fmt.Println("Built enclave identities MATCH on-chain enclave identities.") + } + return + } + // Override the update manifest flag in case the policy does not exist. if deployment.Policy == nil { doUpdate = false @@ -154,7 +226,12 @@ var ( switch doUpdate { case false: - // Ask the user to update the manifest manually. + // Ask the user to update the manifest manually (if the manifest has changed). + if maps.Equal(buildEnclaves, manifestEnclaves) { + fmt.Println("Built enclave identities already match manifest enclave identities.") + break + } + fmt.Println("Update the manifest with the following identities to use the new app:") fmt.Println() fmt.Printf("deployments:\n") @@ -177,6 +254,8 @@ var ( if err = manifest.Save(); err != nil { cobra.CheckErr(fmt.Errorf("failed to update manifest: %w", err)) } + + fmt.Printf("Run `oasis rofl update` to update your ROFL app's on-chain configuration.\n") } }, } @@ -258,6 +337,7 @@ func init() { buildFlags.BoolVar(&offline, "offline", false, "do not perform any operations requiring network access") buildFlags.StringVar(&outputFn, "output", "", "output bundle filename") buildFlags.BoolVar(&doUpdate, "update-manifest", false, "automatically update the manifest") + buildFlags.BoolVar(&doVerify, "verify", false, "verify build against manifest and on-chain state") buildFlags.StringVar(&deploymentName, "deployment", buildRofl.DefaultDeploymentName, "deployment name") Cmd.Flags().AddFlagSet(buildFlags) diff --git a/cmd/rofl/mgmt.go b/cmd/rofl/mgmt.go index 18c37cc..7e5c82f 100644 --- a/cmd/rofl/mgmt.go +++ b/cmd/rofl/mgmt.go @@ -264,6 +264,8 @@ var ( } } } + + fmt.Printf("Run `oasis rofl build --update-manifest` to build your ROFL app.\n") }, } @@ -577,6 +579,8 @@ var ( if err = manifest.Save(); err != nil { cobra.CheckErr(fmt.Errorf("failed to update manifest: %w", err)) } + + fmt.Printf("Run `oasis rofl update` to update your ROFL app's on-chain configuration.\n") }, }