From 69f3065536a9d89fef5223b8bbe0f5fc24f55c92 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 12 Nov 2024 06:27:58 -0600 Subject: [PATCH] Delete remnants of key synchronization. Veil currently does not support horizontal scaling by synchronizing key material across enclaves. This PR deletes all synchronization-related code remnants. --- internal/enclave/keys.go | 69 ---------------- internal/enclave/keys_test.go | 77 ----------------- internal/service/handle/handlers.go | 13 --- internal/service/handle/state.go | 123 ---------------------------- internal/service/routes.go | 3 - internal/service/service.go | 9 +- 6 files changed, 3 insertions(+), 291 deletions(-) delete mode 100644 internal/enclave/keys.go delete mode 100644 internal/enclave/keys_test.go delete mode 100644 internal/service/handle/state.go diff --git a/internal/enclave/keys.go b/internal/enclave/keys.go deleted file mode 100644 index 4603983..0000000 --- a/internal/enclave/keys.go +++ /dev/null @@ -1,69 +0,0 @@ -package enclave - -import ( - "bytes" - "context" - "sync" -) - -// Keys holds key material for veil itself (the HTTPS certificate) and for the -// enclave application (whatever the application wants to "store" in veil). -// These keys are meant to be managed by a leader enclave and -- if horizontal -// scaling is required -- synced to worker enclaves. The struct implements -// getters and setters that allow for thread-safe setting and getting of -// members. -type Keys struct { - sync.Mutex - VeilKey []byte `json:"veil_key"` - VeilCert []byte `json:"veil_cert"` - AppKeys []byte `json:"app_keys"` -} - -// Validate implements the Validator interface for Keys. -func (k *Keys) Validate(_ context.Context) map[string]string { - k.Lock() - defer k.Unlock() - - errs := make(map[string]string) - if len(k.VeilKey) == 0 { - errs["veil_key"] = "veil key is uninitialized" - } - if len(k.VeilCert) == 0 { - errs["veil_cert"] = "veil cert is uninitialized" - } - if len(k.AppKeys) == 0 { - errs["app_keys"] = "app keys are uninitialized" - } - return errs -} - -func (our *Keys) Equal(their *Keys) bool { - our.Lock() - their.Lock() - defer our.Unlock() - defer their.Unlock() - - return bytes.Equal(our.VeilCert, their.VeilCert) && - bytes.Equal(our.VeilKey, their.VeilKey) && - bytes.Equal(our.AppKeys, their.AppKeys) -} - -func (k *Keys) SetAppKeys(appKeys []byte) { - k.Lock() - defer k.Unlock() - - k.AppKeys = appKeys -} - -func (k *Keys) SetVeilKeys(key, cert []byte) { - k.Lock() - defer k.Unlock() - - k.VeilKey = key - k.VeilCert = cert -} - -func (k *Keys) Set(newKeys *Keys) { - k.SetAppKeys(newKeys.AppKeys) - k.SetVeilKeys(newKeys.VeilKey, newKeys.VeilCert) -} diff --git a/internal/enclave/keys_test.go b/internal/enclave/keys_test.go deleted file mode 100644 index 3939b99..0000000 --- a/internal/enclave/keys_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package enclave - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestValidate(t *testing.T) { - cases := []struct { - name string - keys *Keys - numErrs int - }{ - { - "valid", - &Keys{ - VeilKey: []byte("veil_key"), - VeilCert: []byte("veil_cert"), - AppKeys: []byte("app_keys"), - }, - 0, - }, - { - "empty keys", - &Keys{ - VeilKey: []byte(""), - VeilCert: []byte(""), - AppKeys: []byte(""), - }, - 3, - }, - { - "missing veil key", - &Keys{ - VeilCert: []byte("veil_cert"), - AppKeys: []byte("app_keys"), - }, - 1, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - gotErrs := len(c.keys.Validate(context.Background())) - require.Equal(t, c.numErrs, gotErrs) - }) - } -} - -func TestSetAndEqual(t *testing.T) { - var ( - ours = &Keys{ - VeilKey: []byte("foo"), - VeilCert: []byte("foo"), - AppKeys: []byte("foo"), - } - theirs = &Keys{ - VeilKey: []byte("bar"), - VeilCert: []byte("bar"), - AppKeys: []byte("bar"), - } - ) - - // At first, our two sets of keys are not equal. Also, comparison is - // commutative. - assert.False(t, ours.Equal(theirs)) - assert.False(t, theirs.Equal(ours)) - - ours.Set(theirs) - - // Keys should now be equal. - assert.True(t, ours.Equal(theirs)) - assert.True(t, theirs.Equal(ours)) -} diff --git a/internal/service/handle/handlers.go b/internal/service/handle/handlers.go index f26d20b..ed15d43 100644 --- a/internal/service/handle/handlers.go +++ b/internal/service/handle/handlers.go @@ -3,7 +3,6 @@ package handle import ( "crypto/sha256" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -17,18 +16,6 @@ import ( "github.com/Amnesic-Systems/veil/internal/util" ) -const ( - // The maximum length of the key material (in bytes) that enclave - // applications can PUT to our HTTP API. - maxKeyMaterialLen = 1024 * 1024 -) - -var ( - errFailedReqBody = errors.New("failed to read request body") - errDesignationInProgress = errors.New("leader designation in progress") - errEndpointGone = errors.New("endpoint not meant to be used") -) - // Index informs the visitor that this host runs inside an enclave. This is // useful for testing. func Index(cfg *config.Config) http.HandlerFunc { diff --git a/internal/service/handle/state.go b/internal/service/handle/state.go deleted file mode 100644 index d041339..0000000 --- a/internal/service/handle/state.go +++ /dev/null @@ -1,123 +0,0 @@ -package handle - -import ( - "io" - "log" - "net/http" - - "github.com/Amnesic-Systems/veil/internal/enclave" - "github.com/Amnesic-Systems/veil/internal/httperr" - "github.com/Amnesic-Systems/veil/internal/util" -) - -const ( // TODO: remove this - // The states the enclave can be in relating to key synchronization. - noSync = iota // The enclave is not configured to synchronize keys. - inProgress // Leader designation is in progress. - isLeader // The enclave is the leader. - isWorker // The enclave is a worker. -) - -const ( - msgInProgress = "leader designation is in progress" - msgEndpointGone = "endpoint not meant to be used" - msgSyncDisabled = "key synchronization is disabled" - msgUnknownSyncState = "unknown sync state" -) - -type State struct { - keys *enclave.Keys -} - -// NewState returns a new handler for the enclave's GET and PUT state endpoints. -func NewState(keys *enclave.Keys) http.Handler { - return &State{ - keys: keys, - } -} - -func (s *State) ServeHTTP(w http.ResponseWriter, r *http.Request) { - get := getState(func() int { return 3 }, s.keys) - put := putState(func() int { return 0 }, s.keys) - switch r.Method { - case http.MethodGet: - get(w, r) - case http.MethodPut: - put(w, r) - } -} - -// getState lets the enclave application retrieve previously-set state. This is -// an enclave-internal endpoint that can only be accessed by the trusted enclave -// application. -func getState( - getSyncState func() int, - keys *enclave.Keys, -) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - s := getSyncState() - switch s { - case noSync: - encode(w, http.StatusForbidden, httperr.New(msgSyncDisabled)) - case isLeader: - encode(w, http.StatusGone, httperr.New(msgEndpointGone)) - case inProgress: - encode(w, http.StatusServiceUnavailable, httperr.New(msgInProgress)) - case isWorker: - if errs := keys.Validate(r.Context()); len(errs) > 0 { - encode(w, http.StatusInternalServerError, httperr.New(util.SprintErrs(errs))) - log.Panicf("Enclave has invalid keys: %v", errs) - } else { - encode(w, http.StatusOK, keys) - } - default: - encode(w, http.StatusInternalServerError, httperr.New(msgUnknownSyncState)) - log.Panicf("Enclave is in unknown sync state: %d", s) - } - } -} - -// putState returns a handler that lets the enclave application set -// state that's synchronized with another enclave in case of horizontal -// scaling. The state can be arbitrary bytes. -// -// This is an enclave-internal endpoint that can only be accessed by the -// trusted enclave application. -func putState( - getSyncState func() int, - enclaveKeys *enclave.Keys, -) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - switch getSyncState() { - case noSync: - encode(w, http.StatusForbidden, httperr.New(msgSyncDisabled)) - //http.Error(w, errKeySyncDisabled.Error(), http.StatusForbidden) - case isWorker: - http.Error(w, errEndpointGone.Error(), http.StatusGone) - case inProgress: - http.Error(w, errDesignationInProgress.Error(), http.StatusServiceUnavailable) - case isLeader: - keys, err := io.ReadAll(io.LimitReader(r.Body, maxKeyMaterialLen)) - //keys, err := io.LimitReader(r.Body, maxKeyMaterialLen) - if err != nil { - http.Error(w, errFailedReqBody.Error(), http.StatusInternalServerError) - return - } - enclaveKeys.SetAppKeys(keys) - w.WriteHeader(http.StatusOK) - - // The leader's application keys have changed. Re-synchronize the key - // material with all registered workers. If synchronization fails for a - // given worker, unregister it. - //log.Printf("Application keys have changed. Re-synchronizing with %d worker(s).", - // workers.length()) - // go workers.forAll( - // func(worker *url.URL) { - // if err := asLeader(enclaveKeys, a).syncWith(worker); err != nil { - // workers.unregister(worker) - // } - // }, - // ) - } - } -} diff --git a/internal/service/routes.go b/internal/service/routes.go index 9a7cf5e..a6d3f6b 100644 --- a/internal/service/routes.go +++ b/internal/service/routes.go @@ -4,7 +4,6 @@ import ( "net/http/httputil" "github.com/Amnesic-Systems/veil/internal/config" - "github.com/Amnesic-Systems/veil/internal/enclave" "github.com/Amnesic-Systems/veil/internal/service/attestation" "github.com/Amnesic-Systems/veil/internal/service/handle" "github.com/go-chi/chi/v5" @@ -38,7 +37,6 @@ func addExternalPublicRoutes( func addInternalRoutes( r *chi.Mux, config *config.Config, - keys *enclave.Keys, hashes *attestation.Hashes, appReady chan struct{}, ) { @@ -51,5 +49,4 @@ func addInternalRoutes( } r.Get("/enclave/hashes", handle.Hashes(hashes)) r.Post("/enclave/hash", handle.AppHash(hashes.SetAppHash)) - r.Handle("/enclave/state", handle.NewState(keys)) } diff --git a/internal/service/service.go b/internal/service/service.go index 08b6ca4..d37d643 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -38,20 +38,18 @@ func Run( log.Fatalf("Failed to set up system: %v", err) } - // Initialize the enclave keys for enclave synchronization. + // Create a TLS certificate for the external Web server. cert, key, err := httputil.CreateCertificate(config.FQDN) if err != nil { log.Fatalf("Failed to create certificate: %v", err) } - keys := new(enclave.Keys) - keys.SetVeilKeys(key, cert) // Initialize hashes for the attestation document. hashes := new(attestation.Hashes) hashes.SetTLSHash(addr.Of(sha256.Sum256(cert))) // Initialize Web servers. - intSrv := newIntSrv(config, keys, hashes, appReady) + intSrv := newIntSrv(config, hashes, appReady) builder := attestation.NewBuilder( attester, attestation.WithHashes(hashes), @@ -143,12 +141,11 @@ func startAllWebSrvs( func newIntSrv( config *config.Config, - keys *enclave.Keys, hashes *attestation.Hashes, appReady chan struct{}, ) *http.Server { r := chi.NewRouter() - addInternalRoutes(r, config, keys, hashes, appReady) + addInternalRoutes(r, config, hashes, appReady) return &http.Server{ Addr: net.JoinHostPort("127.0.0.1", config.IntPort),