Repository: TBD54566975/ssi-service
Pull request #110 (2022-09-24 04:03:10)

Support key access in all services
A few things:

- Types to support an abstraction over `string` and `[]byte` request/responses for key access
- Added key storage to all services
- Swapped out key storage for the DID service to use the key store
- Found a few issues with manifest, swapped out the impl to rely on the credential service instead of building credentials directly. Added a number of TODOs to go over with @nitro-neal 
- Refactored some tests to mock out test services/routers a bit more uniformly

next up: actually signing / verifying objects

codecov-commenter: # [Codecov](https://codecov.io/gh/TBD54566975/ssi-service/pull/110?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) Report
> Merging [#110](https://codecov.io/gh/TBD54566975/ssi-service/pull/110?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (8d77c81) into [main](https://codecov.io/gh/TBD54566975/ssi-service/commit/0232fb77b82b21ebcb14c3c2e0de26bb865f3b7b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) (0232fb7) will **decrease** coverage by `0.19%`.
> The diff coverage is `26.66%`.

```diff
@@            Coverage Diff             @@
##             main     #110      +/-   ##
==========================================
- Coverage   27.76%   27.56%   -0.20%     
==========================================
  Files          16       16              
  Lines        1059     1110      +51     
==========================================
+ Hits          294      306      +12     
- Misses        723      758      +35     
- Partials       42       46       +4     
```


| [Impacted Files](https://codecov.io/gh/TBD54566975/ssi-service/pull/110?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975) | Coverage Δ | |
|---|---|---|
| [config/config.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-Y29uZmlnL2NvbmZpZy5nbw==) | `9.75% <0.00%> (-2.75%)` | :arrow_down: |
| [pkg/server/router/keystore.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9yb3V0ZXIva2V5c3RvcmUuZ28=) | `13.55% <ø> (ø)` | |
| [pkg/service/keystore/keystore.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZpY2Uva2V5c3RvcmUva2V5c3RvcmUuZ28=) | `13.79% <0.00%> (-3.05%)` | :arrow_down: |
| [internal/keyaccess/jwt.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-aW50ZXJuYWwva2V5YWNjZXNzL2p3dC5nbw==) | `63.07% <55.17%> (-8.63%)` | :arrow_down: |
| [internal/keyaccess/dataintegrity.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-aW50ZXJuYWwva2V5YWNjZXNzL2RhdGFpbnRlZ3JpdHkuZ28=) | `59.09% <100.00%> (ø)` | |
| [internal/util/crypto.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-aW50ZXJuYWwvdXRpbC9jcnlwdG8uZ28=) | `38.29% <100.00%> (ø)` | |
| [pkg/server/server.go](https://codecov.io/gh/TBD54566975/ssi-service/pull/110/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975#diff-cGtnL3NlcnZlci9zZXJ2ZXIuZ28=) | `79.48% <0.00%> (+7.69%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=TBD54566975)


Patch:
diff --git a/config/compose.toml b/config/compose.toml
index 6597c39..332648e 100644
--- a/config/compose.toml
+++ b/config/compose.toml
@@ -23,6 +23,10 @@ log_level = "info"
 storage = "bolt"
 
 # per-service configuration
+[services.keystore]
+name = "keystore"
+password = "default-password"
+
 [services.did]
 name = "did"
 methods = ["key"]
@@ -33,6 +37,9 @@ name = "schema"
 [services.credential]
 name = "credential"
 
+[services.manifest]
+name = "manifest"
+
 [services.dwn]
 name = "dwn"
-dwn_endpoint = "http://localhost:4321"
+dwn_endpoint = "http://localhost:4321"
\ No newline at end of file
diff --git a/config/config.go b/config/config.go
index 37a9895..09bd3e2 100644
--- a/config/config.go
+++ b/config/config.go
@@ -48,10 +48,10 @@ type ServicesConfig struct {
 
 	// Embed all service-specific configs here. The order matters: from which should be instantiated first, to last
 
+	KeyStoreConfig   KeyStoreServiceConfig   `toml:"keystore,omitempty"`
 	DIDConfig        DIDServiceConfig        `toml:"did,omitempty"`
 	SchemaConfig     SchemaServiceConfig     `toml:"schema,omitempty"`
 	CredentialConfig CredentialServiceConfig `toml:"credential,omitempty"`
-	KeyStoreConfig   KeyStoreServiceConfig   `toml:"keystore,omitempty"`
 	ManifestConfig   ManifestServiceConfig   `toml:"manifest,omitempty"`
 	DWNConfig        DWNServiceConfig        `toml:"dwn,omitempty"`
 }
@@ -62,6 +62,20 @@ type BaseServiceConfig struct {
 	Name string `toml:"name"`
 }
 
+type KeyStoreServiceConfig struct {
+	*BaseServiceConfig
+	// Service key password. Used by a KDF whose key is used by a symmetric cypher for key encryption.
+	// The password is salted before usage.
+	ServiceKeyPassword string `toml:"password"`
+}
+
+func (k *KeyStoreServiceConfig) IsEmpty() bool {
+	if k == nil {
+		return true
+	}
+	return reflect.DeepEqual(k, &KeyStoreServiceConfig{})
+}
+
 type DIDServiceConfig struct {
 	*BaseServiceConfig
 	Methods []string `toml:"methods"`
@@ -90,20 +104,34 @@ type CredentialServiceConfig struct {
 	// TODO(gabe) supported key and signature types
 }
 
+func (c *CredentialServiceConfig) IsEmpty() bool {
+	if c == nil {
+		return true
+	}
+	return reflect.DeepEqual(c, &CredentialServiceConfig{})
+}
+
 type ManifestServiceConfig struct {
 	*BaseServiceConfig
 }
 
+func (m *ManifestServiceConfig) IsEmpty() bool {
+	if m == nil {
+		return true
+	}
+	return reflect.DeepEqual(m, &ManifestServiceConfig{})
+}
+
 type DWNServiceConfig struct {
 	*BaseServiceConfig
 	DWNEndpoint string `toml:"dwn_endpoint"`
 }
 
-type KeyStoreServiceConfig struct {
-	*BaseServiceConfig
-	// Service key password. Used by a KDF whose key is used by a symmetric cypher for key encryption.
-	// The password is salted before usage.
-	ServiceKeyPassword string
+func (d *DWNServiceConfig) IsEmpty() bool {
+	if d == nil {
+		return true
+	}
+	return reflect.DeepEqual(d, &DWNServiceConfig{})
 }
 
 // LoadConfig attempts to load a TOML config file from the given path, and coerce it into our object model.
@@ -149,6 +177,10 @@ func LoadConfig(path string) (*SSIServiceConfig, error) {
 	if defaultConfig {
 		config.Services = ServicesConfig{
 			StorageProvider: "bolt",
+			KeyStoreConfig: KeyStoreServiceConfig{
+				BaseServiceConfig:  &BaseServiceConfig{Name: "keystore"},
+				ServiceKeyPassword: "default-password",
+			},
 			DIDConfig: DIDServiceConfig{
 				BaseServiceConfig: &BaseServiceConfig{Name: "did"},
 				Methods:           []string{"key"},
@@ -159,9 +191,8 @@ func LoadConfig(path string) (*SSIServiceConfig, error) {
 			CredentialConfig: CredentialServiceConfig{
 				BaseServiceConfig: &BaseServiceConfig{Name: "credential"},
 			},
-			KeyStoreConfig: KeyStoreServiceConfig{
-				BaseServiceConfig:  &BaseServiceConfig{Name: "keystore"},
-				ServiceKeyPassword: "default-password",
+			ManifestConfig: ManifestServiceConfig{
+				BaseServiceConfig: &BaseServiceConfig{Name: "manifest"},
 			},
 			DWNConfig: DWNServiceConfig{
 				BaseServiceConfig: &BaseServiceConfig{Name: "dwn"},
diff --git a/config/config.toml b/config/config.toml
index aa50313..afd2ff3 100644
--- a/config/config.toml
+++ b/config/config.toml
@@ -21,6 +21,10 @@ log_level = "debug"
 storage = "bolt"
 
 # per-service configuration
+[services.keystore]
+name = "keystore"
+password = "default-password"
+
 [services.did]
 name = "did"
 methods = ["key"]
@@ -29,4 +33,11 @@ methods = ["key"]
 name = "schema"
 
 [services.credential]
-name = "credential"
\ No newline at end of file
+name = "credential"
+
+[services.manifest]
+name = "manifest"
+
+[services.dwn]
+name = "dwn"
+dwn_endpoint = "http://localhost:4321"
\ No newline at end of file
diff --git a/go.mod b/go.mod
index c07bdbc..f0197d8 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/BurntSushi/toml v1.2.0
-	github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd
+	github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b
 	github.com/ardanlabs/conf v1.5.0
 	github.com/dimfeld/httptreemux/v5 v5.4.0
 	github.com/go-playground/locales v0.14.0
diff --git a/go.sum b/go.sum
index f7ee531..6467abe 100644
--- a/go.sum
+++ b/go.sum
@@ -1,13 +1,11 @@
 github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
 github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901 h1:7cT1hMDiWQlsQYNP2U0mxpUjc5AxKVElcAdvTt5amnM=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901/go.mod h1:uXrbtCwqgsbZvL/zM3+DpAOuuIax9qG2aeUhZrGPCck=
 github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220919021815-57be087eca80 h1:1HBBtzkjsgjCYjMVWi6+785SO+Q7kSOOrA0Njw3JON0=
 github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220919021815-57be087eca80/go.mod h1:ZUcjj/CHvtmz48c9GapcbavlTRsN9JZ9pKdT+co/EvY=
 github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220920154030-cbf6b4665a6d h1:NW/9Qg2Z+Yhh6PtzgV/cFwgNz7Sgng3E25IYQiUV34c=
 github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220920154030-cbf6b4665a6d/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd h1:BTbS7+/QsnxvVhP0LwB3JJxnT/9qHC8msEtku2JF4QY=
-github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b h1:0IJJPN8qBGEINcNheyMN/VztIj/Wu9OLzoaEdwfKMWM=
+github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA=
 github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
 github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
diff --git a/internal/keyaccess/dataintegrity.go b/internal/keyaccess/dataintegrity.go
index b120738..ecbbb2c 100644
--- a/internal/keyaccess/dataintegrity.go
+++ b/internal/keyaccess/dataintegrity.go
@@ -47,7 +47,13 @@ func NewDataIntegrityKeyAccess(kid string, key gocrypto.PrivateKey) (*DataIntegr
 	}, nil
 }
 
-func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) ([]byte, error) {
+// DataIntegrityJSON represents a response from a DataIntegrityKeyAccess.Sign() call represented
+// as a serialized JSON object
+type DataIntegrityJSON struct {
+	Data []byte `json:"data" validate:"required"`
+}
+
+func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) (*DataIntegrityJSON, error) {
 	if payload == nil {
 		return nil, errors.New("payload cannot be nil")
 	}
@@ -58,7 +64,7 @@ func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) ([]byte, err
 	if err != nil {
 		return nil, errors.Wrap(err, "could not marshal signed payload")
 	}
-	return signedJSONBytes, nil
+	return &DataIntegrityJSON{Data: signedJSONBytes}, nil
 }
 
 func (ka DataIntegrityKeyAccess) Verify(payload cryptosuite.Provable) error {
diff --git a/internal/keyaccess/jwt.go b/internal/keyaccess/jwt.go
index 807dc9f..bdbaa2e 100644
--- a/internal/keyaccess/jwt.go
+++ b/internal/keyaccess/jwt.go
@@ -42,44 +42,61 @@ func NewJWKKeyAccess(kid string, key gocrypto.PrivateKey) (*JWKKeyAccess, error)
 	}, nil
 }
 
-func (ka JWKKeyAccess) Sign(payload map[string]interface{}) ([]byte, error) {
+// A JWKToken is a utility that wraps a string representation of a JSON Web Token.
+type JWKToken struct {
+	Token string `json:"token" validate:"required"`
+}
+
+func (ka JWKKeyAccess) Sign(payload map[string]interface{}) (*JWKToken, error) {
 	if payload == nil {
 		return nil, errors.New("payload cannot be nil")
 	}
-	return ka.SignJWT(payload)
+	tokenBytes, err := ka.SignJWT(payload)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not sign payload")
+	}
+	return &JWKToken{Token: string(tokenBytes)}, nil
 }
 
-func (ka JWKKeyAccess) Verify(token string) error {
-	if token == "" {
+func (ka JWKKeyAccess) Verify(token JWKToken) error {
+	if token.Token == "" {
 		return errors.New("token cannot be empty")
 	}
-	return ka.VerifyJWT(token)
+	return ka.VerifyJWT(token.Token)
 }
 
-func (ka JWKKeyAccess) SignVerifiableCredential(credential credential.VerifiableCredential) ([]byte, error) {
+func (ka JWKKeyAccess) SignVerifiableCredential(credential credential.VerifiableCredential) (*JWKToken, error) {
 	if err := credential.IsValid(); err != nil {
 		return nil, errors.New("cannot sign invalid credential")
 	}
-	return signing.SignVerifiableCredentialJWT(ka.JWTSigner, credential)
+	tokenBytes, err := signing.SignVerifiableCredentialJWT(ka.JWTSigner, credential)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not sign credential")
+	}
+	return &JWKToken{Token: string(tokenBytes)}, nil
 }
 
-func (ka JWKKeyAccess) VerifyVerifiableCredential(token string) (*credential.VerifiableCredential, error) {
-	if token == "" {
+func (ka JWKKeyAccess) VerifyVerifiableCredential(token JWKToken) (*credential.VerifiableCredential, error) {
+	if token.Token == "" {
 		return nil, errors.New("token cannot be empty")
 	}
-	return signing.VerifyVerifiableCredentialJWT(ka.JWTVerifier, token)
+	return signing.VerifyVerifiableCredentialJWT(ka.JWTVerifier, token.Token)
 }
 
-func (ka JWKKeyAccess) SignVerifiablePresentation(presentation credential.VerifiablePresentation) ([]byte, error) {
+func (ka JWKKeyAccess) SignVerifiablePresentation(presentation credential.VerifiablePresentation) (*JWKToken, error) {
 	if err := presentation.IsValid(); err != nil {
 		return nil, errors.New("cannot sign invalid presentation")
 	}
-	return signing.SignVerifiablePresentationJWT(ka.JWTSigner, presentation)
+	tokenBytes, err := signing.SignVerifiablePresentationJWT(ka.JWTSigner, presentation)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not sign presentation")
+	}
+	return &JWKToken{Token: string(tokenBytes)}, nil
 }
 
-func (ka JWKKeyAccess) VerifyVerifiablePresentation(token string) (*credential.VerifiablePresentation, error) {
-	if token == "" {
+func (ka JWKKeyAccess) VerifyVerifiablePresentation(token JWKToken) (*credential.VerifiablePresentation, error) {
+	if token.Token == "" {
 		return nil, errors.New("token cannot be empty")
 	}
-	return signing.VerifyVerifiablePresentationJWT(ka.JWTVerifier, token)
+	return signing.VerifyVerifiablePresentationJWT(ka.JWTVerifier, token.Token)
 }
diff --git a/internal/util/crypto.go b/internal/util/crypto.go
index 9ecdc21..d53cd2b 100644
--- a/internal/util/crypto.go
+++ b/internal/util/crypto.go
@@ -57,11 +57,11 @@ func XChaCha20Poly1305Decrypt(key, data []byte) ([]byte, error) {
 	nonce, ciphertext := data[:aead.NonceSize()], data[aead.NonceSize():]
 
 	// Decrypt the message and check it wasn't tampered with.
-	decyrpted, err := aead.Open(nil, nonce, ciphertext, nil)
+	decrypted, err := aead.Open(nil, nonce, ciphertext, nil)
 	if err != nil {
 		return nil, errors.Wrap(err, "could not decrypt data")
 	}
-	return decyrpted, nil
+	return decrypted, nil
 }
 
 // Argon2KeyGen returns an encoded string generation of a key generated using the go crypto argon2 impl
diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go
index c8ab631..39ba8b4 100644
--- a/pkg/server/router/manifest.go
+++ b/pkg/server/router/manifest.go
@@ -3,10 +3,12 @@ package router
 import (
 	"context"
 	"fmt"
+	"net/http"
+
 	"github.com/TBD54566975/ssi-sdk/credential"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
+
 	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
-	"net/http"
 
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -214,7 +216,7 @@ func (mr ManifestRouter) SubmitApplication(ctx context.Context, w http.ResponseW
 	}
 
 	req := request.ToServiceRequest()
-	submitApplicationResponse, err := mr.service.SubmitApplication(req)
+	submitApplicationResponse, err := mr.service.ProcessApplicationSubmission(req)
 	if err != nil {
 		errMsg := "could not submit application"
 		logrus.WithError(err).Error(errMsg)
diff --git a/pkg/service/credential/credential.go b/pkg/service/credential/credential.go
index 70c4847..9da063f 100644
--- a/pkg/service/credential/credential.go
+++ b/pkg/service/credential/credential.go
@@ -11,12 +11,16 @@ import (
 	"github.com/tbd54566975/ssi-service/internal/util"
 	credstorage "github.com/tbd54566975/ssi-service/pkg/service/credential/storage"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
 
 type Service struct {
 	storage credstorage.Storage
 	config  config.CredentialServiceConfig
+
+	// external dependencies
+	keyStore *keystore.Service
 }
 
 func (s Service) Type() framework.Type {
@@ -37,15 +41,16 @@ func (s Service) Config() config.CredentialServiceConfig {
 	return s.config
 }
 
-func NewCredentialService(config config.CredentialServiceConfig, s storage.ServiceStorage) (*Service, error) {
+func NewCredentialService(config config.CredentialServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) {
 	credentialStorage, err := credstorage.NewCredentialStorage(s)
 	if err != nil {
 		errMsg := "could not instantiate storage for the credential service"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 	return &Service{
-		storage: credentialStorage,
-		config:  config,
+		storage:  credentialStorage,
+		config:   config,
+		keyStore: keyStore,
 	}, nil
 }
 
@@ -63,7 +68,6 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede
 	// check if there's a conflict with subject ID
 	if id, ok := request.Data[credential.VerifiableCredentialIDProperty]; ok && id != request.Subject {
 		errMsg := fmt.Sprintf("cannot set subject<%s>, data already contains a different ID value: %s", request.Subject, id)
-		logrus.Error(errMsg)
 		return nil, util.LoggingNewError(errMsg)
 	}
 
diff --git a/pkg/service/did/did.go b/pkg/service/did/did.go
index 0c45951..449732f 100644
--- a/pkg/service/did/did.go
+++ b/pkg/service/did/did.go
@@ -2,11 +2,14 @@ package did
 
 import (
 	"fmt"
+
 	"github.com/pkg/errors"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
 	didstorage "github.com/tbd54566975/ssi-service/pkg/service/did/storage"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
 
@@ -21,14 +24,59 @@ type Service struct {
 	handlers map[Method]MethodHandler
 	storage  didstorage.Storage
 	config   config.DIDServiceConfig
+
+	// external dependencies
+	keyStore *keystore.Service
 }
 
-func (s Service) Type() framework.Type {
+// MethodHandler describes the functionality of *all* possible DID service, regardless of method
+type MethodHandler interface {
+	CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error)
+	GetDID(request GetDIDRequest) (*GetDIDResponse, error)
+}
+
+func NewDIDService(config config.DIDServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) {
+	didStorage, err := didstorage.NewDIDStorage(s)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not instantiate DID storage for the DID service")
+	}
+	svc := Service{
+		storage:  didStorage,
+		handlers: make(map[Method]MethodHandler),
+		keyStore: keyStore,
+	}
+
+	// instantiate all handlers for DID methods
+	for _, m := range config.Methods {
+		if err := svc.instantiateHandlerForMethod(Method(m)); err != nil {
+			return nil, errors.Wrap(err, "could not instantiate DID service")
+		}
+	}
+	return &svc, nil
+}
+
+func (s *Service) instantiateHandlerForMethod(method Method) error {
+	switch method {
+	case KeyMethod:
+		handler, err := newKeyDIDHandler(s.storage, s.keyStore)
+		if err != nil {
+			err := fmt.Errorf("could not instnatiate did:%s handler", KeyMethod)
+			return util.LoggingError(err)
+		}
+		s.handlers[method] = handler
+	default:
+		err := fmt.Errorf("unsupported DID method: %s", method)
+		return util.LoggingError(err)
+	}
+	return nil
+}
+
+func (s *Service) Type() framework.Type {
 	return framework.DID
 }
 
 // Status is a self-reporting status for the DID service.
-func (s Service) Status() framework.Status {
+func (s *Service) Status() framework.Status {
 	if s.storage == nil || len(s.handlers) == 0 {
 		return framework.Status{
 			Status:  framework.StatusNotReady,
@@ -38,11 +86,11 @@ func (s Service) Status() framework.Status {
 	return framework.Status{Status: framework.StatusReady}
 }
 
-func (s Service) Config() config.DIDServiceConfig {
+func (s *Service) Config() config.DIDServiceConfig {
 	return s.config
 }
 
-func (s Service) GetSupportedMethods() GetSupportedMethodsResponse {
+func (s *Service) GetSupportedMethods() GetSupportedMethodsResponse {
 	var methods []Method
 	for method := range s.handlers {
 		methods = append(methods, method)
@@ -50,7 +98,7 @@ func (s Service) GetSupportedMethods() GetSupportedMethodsResponse {
 	return GetSupportedMethodsResponse{Methods: methods}
 }
 
-func (s Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse, error) {
+func (s *Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse, error) {
 	handler, err := s.getHandler(request.Method)
 	if err != nil {
 		errMsg := fmt.Sprintf("could not get handler for method<%s>", request.Method)
@@ -59,7 +107,7 @@ func (s Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse
 	return handler.CreateDID(request)
 }
 
-func (s Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) {
+func (s *Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) {
 	handler, err := s.getHandler(request.Method)
 	if err != nil {
 		errMsg := fmt.Sprintf("could not get handler for method<%s>", request.Method)
@@ -68,7 +116,7 @@ func (s Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error)
 	return handler.GetDID(request)
 }
 
-func (s Service) getHandler(method Method) (MethodHandler, error) {
+func (s *Service) getHandler(method Method) (MethodHandler, error) {
 	handler, ok := s.handlers[method]
 	if !ok {
 		err := fmt.Errorf("could not get handler for DID method: %s", method)
@@ -76,44 +124,3 @@ func (s Service) getHandler(method Method) (MethodHandler, error) {
 	}
 	return handler, nil
 }
-
-// MethodHandler describes the functionality of *all* possible DID service, regardless of method
-type MethodHandler interface {
-	CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error)
-	GetDID(request GetDIDRequest) (*GetDIDResponse, error)
-}
-
-func NewDIDService(config config.DIDServiceConfig, s storage.ServiceStorage) (*Service, error) {
-	didStorage, err := didstorage.NewDIDStorage(s)
-	if err != nil {
-		return nil, errors.Wrap(err, "could not instantiate DID storage for the DID service")
-	}
-	svc := Service{
-		storage:  didStorage,
-		handlers: make(map[Method]MethodHandler),
-	}
-
-	// instantiate all handlers for DID methods
-	for _, m := range config.Methods {
-		if err := svc.instantiateHandlerForMethod(Method(m)); err != nil {
-			return nil, errors.Wrap(err, "could not instantiate DID service")
-		}
-	}
-	return &svc, nil
-}
-
-func (s *Service) instantiateHandlerForMethod(method Method) error {
-	switch method {
-	case KeyMethod:
-		handler, err := newKeyDIDHandler(s.storage)
-		if err != nil {
-			err := fmt.Errorf("could not instnatiate did:%s handler", KeyMethod)
-			return util.LoggingError(err)
-		}
-		s.handlers[method] = handler
-	default:
-		err := fmt.Errorf("unsupported DID method: %s", method)
-		return util.LoggingError(err)
-	}
-	return nil
-}
diff --git a/pkg/service/did/key.go b/pkg/service/did/key.go
index 3d4a384..822a557 100644
--- a/pkg/service/did/key.go
+++ b/pkg/service/did/key.go
@@ -10,14 +10,16 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/tbd54566975/ssi-service/pkg/service/did/storage"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 )
 
-func newKeyDIDHandler(s storage.Storage) (MethodHandler, error) {
-	return &keyDIDHandler{storage: s}, nil
+func newKeyDIDHandler(s storage.Storage, ks *keystore.Service) (MethodHandler, error) {
+	return &keyDIDHandler{storage: s, keyStore: ks}, nil
 }
 
 type keyDIDHandler struct {
-	storage storage.Storage
+	storage  storage.Storage
+	keyStore *keystore.Service
 }
 
 func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error) {
@@ -29,10 +31,6 @@ func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse,
 	if err != nil {
 		return nil, errors.Wrap(err, "could not create did:key")
 	}
-	privKeyBase58, err := privateKeyToBase58(privKey)
-	if err != nil {
-		return nil, errors.Wrap(err, "could not encode private key as base58")
-	}
 
 	// expand it to the full doc for storage
 	expanded, err := doc.Expand()
@@ -40,18 +38,37 @@ func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse,
 		return nil, errors.Wrap(err, "error generating did:key document")
 	}
 
-	// store it
+	// store metadata in DID storage
+	id := doc.ToString()
 	storedDID := storage.StoredDID{
-		DID:              *expanded,
-		PrivateKeyBase58: privKeyBase58,
+		ID:  id,
+		DID: *expanded,
 	}
 	if err := h.storage.StoreDID(storedDID); err != nil {
 		return nil, errors.Wrap(err, "could not store did:key value")
 	}
 
+	// convert to a serialized format for return to the client
+	privKeyBase58, err := privateKeyToBase58(privKey)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not encode private key as base58")
+	}
+
+	// store private key in key storage
+	keyStoreRequest := keystore.StoreKeyRequest{
+		ID:         id,
+		Type:       request.KeyType,
+		Controller: id,
+		Key:        privKey,
+	}
+
+	if err := h.keyStore.StoreKey(keyStoreRequest); err != nil {
+		return nil, errors.Wrap(err, "could not store did:key private key")
+	}
+
 	return &CreateDIDResponse{
 		DID:        storedDID.DID,
-		PrivateKey: storedDID.PrivateKeyBase58,
+		PrivateKey: privKeyBase58,
 	}, nil
 }
 
diff --git a/pkg/service/did/storage/bolt.go b/pkg/service/did/storage/bolt.go
index 779cd68..df2b9b1 100644
--- a/pkg/service/did/storage/bolt.go
+++ b/pkg/service/did/storage/bolt.go
@@ -2,8 +2,10 @@ package storage
 
 import (
 	"fmt"
+
 	"github.com/goccy/go-json"
 	"github.com/pkg/errors"
+
 	"github.com/tbd54566975/ssi-service/internal/util"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
@@ -31,8 +33,8 @@ func NewBoltDIDStorage(db *storage.BoltDB) (*BoltDIDStorage, error) {
 }
 
 func (b BoltDIDStorage) StoreDID(did StoredDID) error {
-	couldNotStoreDIDErr := fmt.Sprintf("could not store DID: %s", did.DID.ID)
-	namespace, err := getNamespaceForDID(did.DID.ID)
+	couldNotStoreDIDErr := fmt.Sprintf("could not store DID: %s", did.ID)
+	namespace, err := getNamespaceForDID(did.ID)
 	if err != nil {
 		return util.LoggingErrorMsg(err, couldNotStoreDIDErr)
 	}
@@ -40,7 +42,7 @@ func (b BoltDIDStorage) StoreDID(did StoredDID) error {
 	if err != nil {
 		return util.LoggingErrorMsg(err, couldNotStoreDIDErr)
 	}
-	return b.db.Write(namespace, did.DID.ID, didBytes)
+	return b.db.Write(namespace, did.ID, didBytes)
 }
 
 func (b BoltDIDStorage) GetDID(id string) (*StoredDID, error) {
diff --git a/pkg/service/did/storage/storage.go b/pkg/service/did/storage/storage.go
index 804aeae..038bdfc 100644
--- a/pkg/service/did/storage/storage.go
+++ b/pkg/service/did/storage/storage.go
@@ -10,9 +10,8 @@ import (
 )
 
 type StoredDID struct {
+	ID  string          `json:"id"`
 	DID did.DIDDocument `json:"did"`
-	// TODO(gabe) split out key storage into a key store service encrypted with a service encryption key
-	PrivateKeyBase58 string `json:"privateKeyBase58"`
 }
 
 type Storage interface {
diff --git a/pkg/service/dwn/dwn.go b/pkg/service/dwn/dwn.go
index de11e23..f3bcec8 100644
--- a/pkg/service/dwn/dwn.go
+++ b/pkg/service/dwn/dwn.go
@@ -2,10 +2,13 @@ package dwn
 
 import (
 	"fmt"
+
 	"github.com/sirupsen/logrus"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
 )
@@ -13,6 +16,9 @@ import (
 type Service struct {
 	config          config.DWNServiceConfig
 	manifestStorage manifeststorage.Storage
+
+	// external dependencies
+	keyStore *keystore.Service
 }
 
 func (s Service) Type() framework.Type {
@@ -34,7 +40,7 @@ func (s Service) Config() config.DWNServiceConfig {
 	return s.config
 }
 
-func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage) (*Service, error) {
+func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) {
 	manifestStorage, err := manifeststorage.NewManifestStorage(s)
 	if err != nil {
 		errMsg := "could not instantiate manifestStorage for the dwn service"
@@ -44,6 +50,7 @@ func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage) (*S
 	return &Service{
 		config:          config,
 		manifestStorage: manifestStorage,
+		keyStore:        keyStore,
 	}, nil
 }
 
diff --git a/pkg/service/keystore/keystore.go b/pkg/service/keystore/keystore.go
index ac9145b..77b7f72 100644
--- a/pkg/service/keystore/keystore.go
+++ b/pkg/service/keystore/keystore.go
@@ -85,6 +85,29 @@ func (s Service) StoreKey(request StoreKeyRequest) error {
 	return nil
 }
 
+func (s Service) GetKey(request GetKeyRequest) (*GetKeyResponse, error) {
+
+	logrus.Debugf("getting key: %+v", request)
+
+	id := request.ID
+	gotKey, err := s.storage.GetKey(id)
+	if err != nil {
+		err := errors.Wrapf(err, "could not get key for key: %s", id)
+		return nil, util.LoggingError(err)
+	}
+	if gotKey == nil {
+		err := errors.Wrapf(err, "key with id<%s> could not be found", id)
+		return nil, util.LoggingError(err)
+	}
+	return &GetKeyResponse{
+		ID:         gotKey.ID,
+		Type:       gotKey.KeyType,
+		Controller: gotKey.Controller,
+		Key:        gotKey.Key,
+		CreatedAt:  gotKey.CreatedAt,
+	}, nil
+}
+
 func (s Service) GetKeyDetails(request GetKeyDetailsRequest) (*GetKeyDetailsResponse, error) {
 
 	logrus.Debugf("getting key: %+v", request)
diff --git a/pkg/service/keystore/model.go b/pkg/service/keystore/model.go
index 2f4afac..25c47ff 100644
--- a/pkg/service/keystore/model.go
+++ b/pkg/service/keystore/model.go
@@ -1,6 +1,8 @@
 package keystore
 
 import (
+	gocrypto "crypto"
+
 	"github.com/TBD54566975/ssi-sdk/crypto"
 )
 
@@ -8,7 +10,19 @@ type StoreKeyRequest struct {
 	ID         string
 	Type       crypto.KeyType
 	Controller string
-	Key        []byte
+	Key        gocrypto.PrivateKey
+}
+
+type GetKeyRequest struct {
+	ID string
+}
+
+type GetKeyResponse struct {
+	ID         string
+	Type       crypto.KeyType
+	Controller string
+	CreatedAt  string
+	Key        gocrypto.PrivateKey
 }
 
 type GetKeyDetailsRequest struct {
diff --git a/pkg/service/keystore/storage/bolt.go b/pkg/service/keystore/storage/bolt.go
index dd4e61c..af6379c 100644
--- a/pkg/service/keystore/storage/bolt.go
+++ b/pkg/service/keystore/storage/bolt.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"github.com/goccy/go-json"
+	"github.com/mr-tron/base58"
 	"github.com/pkg/errors"
 
 	"github.com/tbd54566975/ssi-service/internal/util"
@@ -17,7 +18,8 @@ const (
 )
 
 type BoltKeyStoreStorage struct {
-	db *storage.BoltDB
+	db         *storage.BoltDB
+	serviceKey []byte
 }
 
 func NewBoltKeyStoreStorage(db *storage.BoltDB, key ServiceKey) (*BoltKeyStoreStorage, error) {
@@ -25,7 +27,11 @@ func NewBoltKeyStoreStorage(db *storage.BoltDB, key ServiceKey) (*BoltKeyStoreSt
 		return nil, errors.New("bolt db reference is nil")
 	}
 
-	bolt := &BoltKeyStoreStorage{db: db}
+	keyBytes, err := base58.Decode(key.Base58Key)
+	if err != nil {
+		return nil, errors.Wrap(err, "could not decode service key")
+	}
+	bolt := &BoltKeyStoreStorage{db: db, serviceKey: keyBytes}
 
 	// first, store the service key
 	if err := bolt.storeServiceKey(key); err != nil {
@@ -69,10 +75,17 @@ func (b BoltKeyStoreStorage) StoreKey(key StoredKey) error {
 		errMsg := fmt.Sprintf("could not store key: %s", id)
 		return util.LoggingErrorMsg(err, errMsg)
 	}
-	return b.db.Write(namespace, id, keyBytes)
+
+	// encrypt key before storing
+	encryptedKey, err := util.XChaCha20Poly1305Encrypt(b.serviceKey, keyBytes)
+	if err != nil {
+		return errors.Wrapf(err, "could not encrypt key: %s", key.ID)
+	}
+
+	return b.db.Write(namespace, id, encryptedKey)
 }
 
-func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) {
+func (b BoltKeyStoreStorage) GetKey(id string) (*StoredKey, error) {
 	storedKeyBytes, err := b.db.Read(namespace, id)
 	if err != nil {
 		errMsg := fmt.Sprintf("could not get key details for key: %s", id)
@@ -82,11 +95,26 @@ func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) {
 		err := fmt.Errorf("could not find key details for key: %s", id)
 		return nil, util.LoggingError(err)
 	}
+
+	// decrypt key before unmarshaling
+	decryptedKey, err := util.XChaCha20Poly1305Decrypt(b.serviceKey, storedKeyBytes)
+	if err != nil {
+		return nil, errors.Wrapf(err, "could not decrypt key: %s", id)
+	}
+
 	var stored StoredKey
-	if err := json.Unmarshal(storedKeyBytes, &stored); err != nil {
+	if err := json.Unmarshal(decryptedKey, &stored); err != nil {
 		errMsg := fmt.Sprintf("could not unmarshal stored key: %s", id)
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
+	return &stored, nil
+}
+
+func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) {
+	stored, err := b.GetKey(id)
+	if err != nil {
+		return nil, errors.Wrapf(err, "could not get key details for key: %s", id)
+	}
 	return &KeyDetails{
 		ID:         stored.ID,
 		Controller: stored.Controller,
diff --git a/pkg/service/keystore/storage/storage.go b/pkg/service/keystore/storage/storage.go
index 67799c1..226bd0b 100644
--- a/pkg/service/keystore/storage/storage.go
+++ b/pkg/service/keystore/storage/storage.go
@@ -1,6 +1,7 @@
 package storage
 
 import (
+	gocrypto "crypto"
 	"fmt"
 
 	"github.com/TBD54566975/ssi-sdk/crypto"
@@ -11,11 +12,11 @@ import (
 
 // StoredKey represents a common data model to store data on all key types
 type StoredKey struct {
-	ID         string         `json:"id"`
-	Controller string         `json:"controller"`
-	KeyType    crypto.KeyType `json:"keyType"`
-	Key        []byte         `json:"key"`
-	CreatedAt  string         `json:"createdAt"`
+	ID         string              `json:"id"`
+	Controller string              `json:"controller"`
+	KeyType    crypto.KeyType      `json:"keyType"`
+	Key        gocrypto.PrivateKey `json:"key"`
+	CreatedAt  string              `json:"createdAt"`
 }
 
 // KeyDetails represents a common data model to get information about a key, without revealing the key itself
@@ -27,12 +28,13 @@ type KeyDetails struct {
 }
 
 type ServiceKey struct {
-	Key  string
-	Salt string
+	Base58Key  string
+	Base58Salt string
 }
 
 type Storage interface {
 	StoreKey(key StoredKey) error
+	GetKey(id string) (*StoredKey, error)
 	GetKeyDetails(id string) (*KeyDetails, error)
 }
 
@@ -45,8 +47,8 @@ func NewKeyStoreStorage(s storage.ServiceStorage, serviceKey, serviceKeySalt str
 			return nil, util.LoggingNewError(errMsg)
 		}
 		boltStorage, err := NewBoltKeyStoreStorage(gotBolt, ServiceKey{
-			Key:  serviceKey,
-			Salt: serviceKeySalt,
+			Base58Key:  serviceKey,
+			Base58Salt: serviceKeySalt,
 		})
 		if err != nil {
 			return nil, util.LoggingErrorMsg(err, "could not instantiate key store bolt storage")
diff --git a/pkg/service/manifest/manifest.go b/pkg/service/manifest/manifest.go
index 5be797f..e06dfcb 100644
--- a/pkg/service/manifest/manifest.go
+++ b/pkg/service/manifest/manifest.go
@@ -2,22 +2,28 @@ package manifest
 
 import (
 	"fmt"
-	"github.com/TBD54566975/ssi-sdk/credential"
+
+	credsdk "github.com/TBD54566975/ssi-sdk/credential"
+	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
 	"github.com/sirupsen/logrus"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
-	credentialstorage "github.com/tbd54566975/ssi-service/pkg/service/credential/storage"
+	"github.com/tbd54566975/ssi-service/pkg/service/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"time"
 )
 
 type Service struct {
-	manifestStorage   manifeststorage.Storage
-	credentialStorage credentialstorage.Storage
-	config            config.ManifestServiceConfig
+	manifestStorage manifeststorage.Storage
+	config          config.ManifestServiceConfig
+
+	// external dependencies
+	credential *credential.Service
+	keyStore   *keystore.Service
 }
 
 func (s Service) Type() framework.Type {
@@ -28,14 +34,7 @@ func (s Service) Status() framework.Status {
 	if s.manifestStorage == nil {
 		return framework.Status{
 			Status:  framework.StatusNotReady,
-			Message: "no manifestStorage",
-		}
-	}
-
-	if s.credentialStorage == nil {
-		return framework.Status{
-			Status:  framework.StatusNotReady,
-			Message: "no credentialStorage",
+			Message: "no manifest storage",
 		}
 	}
 
@@ -46,48 +45,41 @@ func (s Service) Config() config.ManifestServiceConfig {
 	return s.config
 }
 
-func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage) (*Service, error) {
+func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, credential *credential.Service) (*Service, error) {
 	manifestStorage, err := manifeststorage.NewManifestStorage(s)
 	if err != nil {
 		errMsg := "could not instantiate manifestStorage for the manifest service"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
-
-	credentialStorage, err := credentialstorage.NewCredentialStorage(s)
-	if err != nil {
-		errMsg := "could not instantiate credentialStorage for the manifest service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
-	}
 	return &Service{
-		manifestStorage:   manifestStorage,
-		credentialStorage: credentialStorage,
-		config:            config,
+		manifestStorage: manifestStorage,
+		config:          config,
+		keyStore:        keyStore,
+		credential:      credential,
 	}, nil
 }
 
 func (s Service) CreateManifest(request CreateManifestRequest) (*CreateManifestResponse, error) {
 	logrus.Debugf("creating manifest: %+v", request)
 
-	mfst := request.Manifest
-	if err := mfst.IsValid(); err != nil {
-		errMsg := "manifest is not valid"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+	m := request.Manifest
+	if err := m.IsValid(); err != nil {
+		return nil, util.LoggingErrorMsg(err, "manifest is not valid")
 	}
 
 	// store the manifest
 	storageRequest := manifeststorage.StoredManifest{
-		ID:       mfst.ID,
-		Manifest: mfst,
-		Issuer:   mfst.Issuer.ID,
+		ID:       m.ID,
+		Manifest: m,
+		Issuer:   m.Issuer.ID,
 	}
 
 	if err := s.manifestStorage.StoreManifest(storageRequest); err != nil {
-		errMsg := "could not store manifest"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not store manifest")
 	}
 
 	// return the result
-	response := CreateManifestResponse{Manifest: mfst}
+	response := CreateManifestResponse{Manifest: m}
 	return &response, nil
 }
 
@@ -109,13 +101,12 @@ func (s Service) GetManifests() (*GetManifestsResponse, error) {
 	gotManifests, err := s.manifestStorage.GetManifests()
 
 	if err != nil {
-		errMsg := fmt.Sprintf("could not get manifests(s)")
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not get manifests(s)")
 	}
 
 	var manifests []manifest.CredentialManifest
-	for _, manifest := range gotManifests {
-		manifests = append(manifests, manifest.Manifest)
+	for _, m := range gotManifests {
+		manifests = append(manifests, m.Manifest)
 	}
 	response := GetManifestsResponse{Manifests: manifests}
 	return &response, nil
@@ -154,12 +145,11 @@ func isValidApplication(gotManifest *manifeststorage.StoredManifest, application
 	return nil
 }
 
-func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) {
+func (s Service) ProcessApplicationSubmission(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) {
 	credApp := request.Application
 
 	if err := credApp.IsValid(); err != nil {
-		errMsg := "application is not valid"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "application is not valid")
 	}
 
 	gotManifest, err := s.manifestStorage.GetManifest(credApp.ManifestID)
@@ -169,8 +159,7 @@ func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApp
 
 	// validate
 	if err := isValidApplication(gotManifest, credApp); err != nil {
-		errMsg := fmt.Sprintf("could not validate application")
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not validate application")
 	}
 
 	// store the application
@@ -186,59 +175,57 @@ func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApp
 	}
 
 	// build the credential response
+	// TODO(gabe) need to check if this can be fulfilled and conditionally return success/denial
 	responseBuilder := manifest.NewCredentialResponseBuilder(request.Application.ManifestID)
-	responseBuilder.SetApplicationID(credApp.ID)
-	responseBuilder.SetFulfillment(credApp.PresentationSubmission.DescriptorMap)
-
-	credRes, err := responseBuilder.Build()
-	if err != nil {
-		errMsg := "could not build response"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+	if err := responseBuilder.SetApplicationID(credApp.ID); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set application id")
 	}
 
-	// store the response
-	responseStorageRequest := manifeststorage.StoredResponse{
-		ID:         credRes.ID,
-		Response:   *credRes,
-		ManifestID: request.Application.ManifestID,
-	}
-
-	var creds []credential.VerifiableCredential
+	var creds []credsdk.VerifiableCredential
 	for _, od := range gotManifest.Manifest.OutputDescriptors {
-
-		if err := s.manifestStorage.StoreResponse(responseStorageRequest); err != nil {
-			errMsg := "could not store response"
-			return nil, util.LoggingErrorMsg(err, errMsg)
+		credentialRequest := credential.CreateCredentialRequest{
+			Issuer:     gotManifest.Manifest.Issuer.ID,
+			Subject:    request.RequesterDID,
+			JSONSchema: od.Schema,
+			// TODO(gabe) need to add in data here to match the request + schema
+			Data: map[string]interface{}{},
 		}
 
-		credentialBuilder := credential.NewVerifiableCredentialBuilder()
-		credentialBuilder.SetIssuer(gotManifest.Manifest.Issuer.ID)
-		credentialBuilder.SetCredentialSubject(map[string]interface{}{
-			"id": request.RequesterDID,
-		})
-		credentialBuilder.SetIssuanceDate(time.Now().Format(time.RFC3339))
-
-		cred, err := credentialBuilder.Build()
+		credentialResponse, err := s.credential.CreateCredential(credentialRequest)
 		if err != nil {
-			errMsg := "could not build credential"
-			return nil, util.LoggingErrorMsg(err, errMsg)
+			return nil, util.LoggingErrorMsg(err, "could not create credential")
 		}
 
-		credentialStorageRequest := credentialstorage.StoredCredential{
-			ID:           cred.ID,
-			Credential:   *cred,
-			Issuer:       gotManifest.Manifest.Issuer.ID,
-			Subject:      request.RequesterDID,
-			Schema:       od.Schema,
-			IssuanceDate: time.Now().Format(time.RFC3339),
-		}
+		creds = append(creds, credentialResponse.Credential)
+	}
 
-		if err := s.credentialStorage.StoreCredential(credentialStorageRequest); err != nil {
-			errMsg := "could not store credential"
-			return nil, util.LoggingErrorMsg(err, errMsg)
-		}
+	var descriptors []exchange.SubmissionDescriptor
+	for i, cred := range creds {
+		// TODO(gabe) build this correctly based on the generated credential format and envelope type
+		descriptors = append(descriptors, exchange.SubmissionDescriptor{
+			ID:     cred.ID,
+			Format: string(exchange.JWTVC),
+			Path:   fmt.Sprintf("$.verifiableCredential[%d]", i),
+		})
+	}
 
-		creds = append(creds, *cred)
+	// set the information for the fulfilled credentials in the response
+	if err := responseBuilder.SetFulfillment(descriptors); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment")
+	}
+	credRes, err := responseBuilder.Build()
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not build response")
+	}
+
+	// store the response we've generated
+	storeResponseRequest := manifeststorage.StoredResponse{
+		ID:         credRes.ID,
+		Response:   *credRes,
+		ManifestID: request.Application.ManifestID,
+	}
+	if err := s.manifestStorage.StoreResponse(storeResponseRequest); err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not store manifest response")
 	}
 
 	response := SubmitApplicationResponse{Response: *credRes, Credential: creds}
@@ -265,8 +252,7 @@ func (s Service) GetApplications() (*GetApplicationsResponse, error) {
 
 	gotApps, err := s.manifestStorage.GetApplications()
 	if err != nil {
-		errMsg := fmt.Sprintf("could not get application(s)")
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not get application(s)")
 	}
 
 	var apps []manifest.CredentialApplication
@@ -310,8 +296,7 @@ func (s Service) GetResponses() (*GetResponsesResponse, error) {
 
 	gotResponses, err := s.manifestStorage.GetResponses()
 	if err != nil {
-		errMsg := fmt.Sprintf("could not get response(s)")
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not get response(s)")
 	}
 
 	var responses []manifest.CredentialResponse
diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go
index 9a94780..9554f72 100644
--- a/pkg/service/manifest/storage/storage.go
+++ b/pkg/service/manifest/storage/storage.go
@@ -2,6 +2,7 @@ package storage
 
 import (
 	"fmt"
+
 	"github.com/TBD54566975/ssi-sdk/credential/manifest"
 
 	"github.com/tbd54566975/ssi-service/internal/util"
@@ -27,19 +28,26 @@ type StoredResponse struct {
 }
 
 type Storage interface {
-	// Credential Manifest
+	CredentialManifestStorage
+	CredentialApplicationStorage
+	CredentialResponseStorage
+}
+
+type CredentialManifestStorage interface {
 	StoreManifest(manifest StoredManifest) error
 	GetManifest(id string) (*StoredManifest, error)
 	GetManifests() ([]StoredManifest, error)
 	DeleteManifest(id string) error
+}
 
-	// Credential Application
+type CredentialApplicationStorage interface {
 	StoreApplication(application StoredApplication) error
 	GetApplication(id string) (*StoredApplication, error)
 	GetApplications() ([]StoredApplication, error)
 	DeleteApplication(id string) error
+}
 
-	// Credential Response
+type CredentialResponseStorage interface {
 	StoreResponse(response StoredResponse) error
 	GetResponse(id string) (*StoredResponse, error)
 	GetResponses() ([]StoredResponse, error)
diff --git a/pkg/service/schema/schema.go b/pkg/service/schema/schema.go
index 40c52c5..a675077 100644
--- a/pkg/service/schema/schema.go
+++ b/pkg/service/schema/schema.go
@@ -2,22 +2,28 @@ package schema
 
 import (
 	"fmt"
+	"time"
+
 	"github.com/TBD54566975/ssi-sdk/credential/schema"
 	schemalib "github.com/TBD54566975/ssi-sdk/schema"
 	"github.com/goccy/go-json"
 	"github.com/google/uuid"
 	"github.com/pkg/errors"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/internal/util"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	schemastorage "github.com/tbd54566975/ssi-service/pkg/service/schema/storage"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"time"
 )
 
 type Service struct {
 	storage schemastorage.Storage
 	config  config.SchemaServiceConfig
+
+	// external dependencies
+	keyStore *keystore.Service
 }
 
 func (s Service) Type() framework.Type {
@@ -38,15 +44,16 @@ func (s Service) Config() config.SchemaServiceConfig {
 	return s.config
 }
 
-func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage) (*Service, error) {
+func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) {
 	schemaStorage, err := schemastorage.NewSchemaStorage(s)
 	if err != nil {
 		errMsg := "could not instantiate storage for the schema service"
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 	return &Service{
-		storage: schemaStorage,
-		config:  config,
+		storage:  schemaStorage,
+		config:   config,
+		keyStore: keyStore,
 	}, nil
 }
 
diff --git a/pkg/service/service.go b/pkg/service/service.go
index d31a534..6122e42 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -9,6 +9,7 @@ import (
 	"github.com/tbd54566975/ssi-service/pkg/service/did"
 	"github.com/tbd54566975/ssi-service/pkg/service/dwn"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
 	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
 	"github.com/tbd54566975/ssi-service/pkg/service/schema"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
@@ -39,12 +40,24 @@ func validateServiceConfig(config config.ServicesConfig) error {
 	if !storage.IsStorageAvailable(config.StorageProvider) {
 		return fmt.Errorf("%s storage provider configured, but not available", config.StorageProvider)
 	}
+	if config.KeyStoreConfig.IsEmpty() {
+		return fmt.Errorf("%s no config provided", framework.KeyStore)
+	}
 	if config.DIDConfig.IsEmpty() {
 		return fmt.Errorf("%s no config provided", framework.DID)
 	}
 	if config.SchemaConfig.IsEmpty() {
 		return fmt.Errorf("%s no config provided", framework.Schema)
 	}
+	if config.CredentialConfig.IsEmpty() {
+		return fmt.Errorf("%s no config provided", framework.Credential)
+	}
+	if config.ManifestConfig.IsEmpty() {
+		return fmt.Errorf("%s no config provided", framework.Manifest)
+	}
+	if config.DWNConfig.IsEmpty() {
+		return fmt.Errorf("%s no config provided", framework.DWN)
+	}
 	return nil
 }
 
@@ -61,35 +74,35 @@ func instantiateServices(config config.ServicesConfig) ([]framework.Service, err
 		return nil, util.LoggingErrorMsg(err, errMsg)
 	}
 
-	didService, err := did.NewDIDService(config.DIDConfig, storageProvider)
+	keyStoreService, err := keystore.NewKeyStoreService(config.KeyStoreConfig, storageProvider)
 	if err != nil {
-		errMsg := "could not instantiate the DID service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not instantiate keystore service")
 	}
 
-	schemaService, err := schema.NewSchemaService(config.SchemaConfig, storageProvider)
+	didService, err := did.NewDIDService(config.DIDConfig, storageProvider, keyStoreService)
 	if err != nil {
-		errMsg := "could not instantiate the schema service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not instantiate the DID service")
 	}
 
-	credentialService, err := credential.NewCredentialService(config.CredentialConfig, storageProvider)
+	schemaService, err := schema.NewSchemaService(config.SchemaConfig, storageProvider, keyStoreService)
 	if err != nil {
-		errMsg := "could not instantiate the credential service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not instantiate the schema service")
 	}
 
-	manifestService, err := manifest.NewManifestService(config.ManifestConfig, storageProvider)
+	credentialService, err := credential.NewCredentialService(config.CredentialConfig, storageProvider, keyStoreService)
 	if err != nil {
-		errMsg := "could not instantiate the manifest service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not instantiate the credential service")
 	}
 
-	dwnService, err := dwn.NewDWNService(config.DWNConfig, storageProvider)
+	manifestService, err := manifest.NewManifestService(config.ManifestConfig, storageProvider, keyStoreService, credentialService)
 	if err != nil {
-		errMsg := "could not instantiate the dwn service"
-		return nil, util.LoggingErrorMsg(err, errMsg)
+		return nil, util.LoggingErrorMsg(err, "could not instantiate the manifest service")
+	}
+
+	dwnService, err := dwn.NewDWNService(config.DWNConfig, storageProvider, keyStoreService)
+	if err != nil {
+		return nil, util.LoggingErrorMsg(err, "could not instantiate the dwn service")
 	}
 
-	return []framework.Service{didService, schemaService, credentialService, manifestService, dwnService}, nil
+	return []framework.Service{keyStoreService, didService, schemaService, credentialService, manifestService, dwnService}, nil
 }


Test patch:
diff --git a/internal/keyaccess/dataintegrity_test.go b/internal/keyaccess/dataintegrity_test.go
index f6a8e79..da42819 100644
--- a/internal/keyaccess/dataintegrity_test.go
+++ b/internal/keyaccess/dataintegrity_test.go
@@ -53,7 +53,7 @@ func TestDataIntegrityKeyAccessSignVerify(t *testing.T) {
 		assert.NotEmpty(tt, signedCred)
 
 		var cred credential.VerifiableCredential
-		err = json.Unmarshal(signedCred, &cred)
+		err = json.Unmarshal(signedCred.Data, &cred)
 		assert.NoError(tt, err)
 
 		// verify
@@ -104,11 +104,11 @@ func TestDataIntegrityKeyAccessSignVerify(t *testing.T) {
 		assert.NotEmpty(tt, signedPres)
 
 		var pres credential.VerifiablePresentation
-		err = json.Unmarshal(signedPres, &pres)
+		err = json.Unmarshal(signedPres.Data, &pres)
 		assert.NoError(tt, err)
 
 		// verify
 		err = ka.Verify(&pres)
 		assert.NoError(tt, err)
 	})
-}
\ No newline at end of file
+}
diff --git a/internal/keyaccess/jwt_test.go b/internal/keyaccess/jwt_test.go
index 0920e06..c1a0073 100644
--- a/internal/keyaccess/jwt_test.go
+++ b/internal/keyaccess/jwt_test.go
@@ -50,11 +50,11 @@ func TestJWKKeyAccessSignVerify(t *testing.T) {
 		data := map[string]interface{}{
 			"test": "test",
 		}
-		tokenBytes, err := ka.Sign(data)
+		token, err := ka.Sign(data)
 		assert.NoError(tt, err)
-		assert.NotEmpty(tt, tokenBytes)
+		assert.NotEmpty(tt, token)
 
-		err = ka.Verify(string(tokenBytes))
+		err = ka.Verify(*token)
 		assert.NoError(tt, err)
 	})
 
@@ -79,7 +79,7 @@ func TestJWKKeyAccessSignVerify(t *testing.T) {
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, ka)
 
-		err = ka.Verify("")
+		err = ka.Verify(JWKToken{})
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "token cannot be empty")
 	})
@@ -101,7 +101,7 @@ func TestJWKKeyAccessSignVerifyCredentials(t *testing.T) {
 		assert.NotEmpty(tt, signedCred)
 
 		// verify
-		verifiedCred, err := ka.VerifyVerifiableCredential(string(signedCred))
+		verifiedCred, err := ka.VerifyVerifiableCredential(*signedCred)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, verifiedCred)
 
@@ -136,7 +136,7 @@ func TestJWKKeyAccessSignVerifyCredentials(t *testing.T) {
 		assert.NotEmpty(tt, ka)
 
 		// verify
-		_, err = ka.VerifyVerifiableCredential("bad")
+		_, err = ka.VerifyVerifiableCredential(JWKToken{"bad"})
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "could not verify JWT and its signature")
 	})
@@ -158,7 +158,7 @@ func TestJWKKeyAccessSignVerifyPresentations(t *testing.T) {
 		assert.NotEmpty(tt, signedPres)
 
 		// verify
-		verifiedPres, err := ka.VerifyVerifiablePresentation(string(signedPres))
+		verifiedPres, err := ka.VerifyVerifiablePresentation(*signedPres)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, verifiedPres)
 
@@ -193,7 +193,7 @@ func TestJWKKeyAccessSignVerifyPresentations(t *testing.T) {
 		assert.NotEmpty(tt, ka)
 
 		// verify
-		_, err = ka.VerifyVerifiablePresentation("bad")
+		_, err = ka.VerifyVerifiablePresentation(JWKToken{"bad"})
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "could not verify JWT and its signature")
 	})
diff --git a/pkg/server/router/credential_test.go b/pkg/server/router/credential_test.go
index e7aef24..81dc1dd 100644
--- a/pkg/server/router/credential_test.go
+++ b/pkg/server/router/credential_test.go
@@ -2,16 +2,18 @@ package router
 
 import (
 	"fmt"
+	"os"
+	"testing"
+	"time"
+
 	credsdk "github.com/TBD54566975/ssi-sdk/credential"
 	"github.com/goccy/go-json"
 	"github.com/stretchr/testify/assert"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/pkg/service/credential"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"os"
-	"testing"
-	"time"
 )
 
 func TestCredentialRouter(t *testing.T) {
@@ -40,7 +42,8 @@ func TestCredentialRouter(t *testing.T) {
 		assert.NotEmpty(tt, bolt)
 
 		serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}}
-		credService, err := credential.NewCredentialService(serviceConfig, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService, err := credential.NewCredentialService(serviceConfig, bolt, keyStoreService)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, credService)
 
diff --git a/pkg/server/router/did_test.go b/pkg/server/router/did_test.go
index 6313b46..33c5122 100644
--- a/pkg/server/router/did_test.go
+++ b/pkg/server/router/did_test.go
@@ -35,12 +35,13 @@ func TestDIDRouter(t *testing.T) {
 	})
 
 	t.Run("DID Service Test", func(tt *testing.T) {
-		bolt, err := storage.NewBoltDB()
+		db, err := storage.NewBoltDB()
 		assert.NoError(tt, err)
-		assert.NotEmpty(tt, bolt)
+		assert.NotEmpty(tt, db)
 
+		keyStoreService := testKeyStoreService(tt, db)
 		serviceConfig := config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}}
-		didService, err := did.NewDIDService(serviceConfig, bolt)
+		didService, err := did.NewDIDService(serviceConfig, db, keyStoreService)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, didService)
 
diff --git a/pkg/server/router/dwn_test.go b/pkg/server/router/dwn_test.go
index 44e1ef4..95ce3e9 100644
--- a/pkg/server/router/dwn_test.go
+++ b/pkg/server/router/dwn_test.go
@@ -1,13 +1,15 @@
 package router
 
 import (
+	"os"
+	"testing"
+
 	"github.com/stretchr/testify/assert"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/pkg/service/dwn"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"os"
-	"testing"
 )
 
 func TestDWNRouter(t *testing.T) {
@@ -36,7 +38,8 @@ func TestDWNRouter(t *testing.T) {
 		assert.NotEmpty(tt, bolt)
 
 		serviceConfig := config.DWNServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "dwn"}}
-		dwnService, err := dwn.NewDWNService(serviceConfig, bolt)
+		keyStore := testKeyStoreService(t, bolt)
+		dwnService, err := dwn.NewDWNService(serviceConfig, bolt, keyStore)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, dwnService)
 
diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go
index c936bde..0ec97dd 100644
--- a/pkg/server/router/manifest_test.go
+++ b/pkg/server/router/manifest_test.go
@@ -1,17 +1,19 @@
 package router
 
 import (
+	"os"
+	"testing"
+
 	"github.com/TBD54566975/ssi-sdk/credential/exchange"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
 	"github.com/TBD54566975/ssi-sdk/crypto"
 	"github.com/google/uuid"
 	"github.com/stretchr/testify/assert"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	"github.com/tbd54566975/ssi-service/pkg/service/manifest"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"os"
-	"testing"
 )
 
 func TestManifestRouter(t *testing.T) {
@@ -40,7 +42,9 @@ func TestManifestRouter(t *testing.T) {
 		assert.NotEmpty(tt, bolt)
 
 		serviceConfig := config.ManifestServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "manifest"}}
-		manifestService, err := manifest.NewManifestService(serviceConfig, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		testCredentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestService, err := manifest.NewManifestService(serviceConfig, bolt, keyStoreService, testCredentialService)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, manifestService)
 
@@ -59,7 +63,7 @@ func TestManifestRouter(t *testing.T) {
 		// good application request
 		createApplicationRequest := getValidApplicationRequest(createdManifest.Manifest.ID, createManifestRequest.Manifest.PresentationDefinition.InputDescriptors[0].ID)
 
-		createdApplication, err := manifestService.SubmitApplication(createApplicationRequest)
+		createdApplication, err := manifestService.ProcessApplicationSubmission(createApplicationRequest)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, createdManifest)
 		assert.NotEmpty(tt, createdApplication.Response.ID)
@@ -111,7 +115,6 @@ func getValidManifestRequest() manifest.CreateManifestRequest {
 }
 
 func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest {
-
 	createApplication := manifestsdk.CredentialApplication{
 		ID:          uuid.New().String(),
 		SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
diff --git a/pkg/server/router/router_test.go b/pkg/server/router/router_test.go
index 7af4d71..4bbf129 100644
--- a/pkg/server/router/router_test.go
+++ b/pkg/server/router/router_test.go
@@ -21,10 +21,10 @@ func (s *testService) Status() framework.Status {
 func (s *testService) Config() config.ServicesConfig {
 	return config.ServicesConfig{
 		StorageProvider:  "bolt",
+		KeyStoreConfig:   config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"},
 		DIDConfig:        config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}},
 		SchemaConfig:     config.SchemaServiceConfig{},
 		CredentialConfig: config.CredentialServiceConfig{},
-		KeyStoreConfig:   config.KeyStoreServiceConfig{},
 		ManifestConfig:   config.ManifestServiceConfig{},
 	}
 }
diff --git a/pkg/server/router/schema_test.go b/pkg/server/router/schema_test.go
index 4c7151e..4a19949 100644
--- a/pkg/server/router/schema_test.go
+++ b/pkg/server/router/schema_test.go
@@ -1,13 +1,15 @@
 package router
 
 import (
+	"os"
+	"testing"
+
 	"github.com/stretchr/testify/assert"
+
 	"github.com/tbd54566975/ssi-service/config"
 	"github.com/tbd54566975/ssi-service/pkg/service/framework"
 	"github.com/tbd54566975/ssi-service/pkg/service/schema"
 	"github.com/tbd54566975/ssi-service/pkg/storage"
-	"os"
-	"testing"
 )
 
 func TestSchemaRouter(t *testing.T) {
@@ -37,7 +39,8 @@ func TestSchemaRouter(t *testing.T) {
 		assert.NotEmpty(tt, bolt)
 
 		serviceConfig := config.SchemaServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "schema"}}
-		schemaService, err := schema.NewSchemaService(serviceConfig, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		schemaService, err := schema.NewSchemaService(serviceConfig, bolt, keyStoreService)
 		assert.NoError(tt, err)
 		assert.NotEmpty(tt, schemaService)
 
diff --git a/pkg/server/router/testutils_test.go b/pkg/server/router/testutils_test.go
new file mode 100644
index 0000000..b6da1c0
--- /dev/null
+++ b/pkg/server/router/testutils_test.go
@@ -0,0 +1,30 @@
+package router
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/tbd54566975/ssi-service/config"
+	"github.com/tbd54566975/ssi-service/pkg/service/credential"
+	"github.com/tbd54566975/ssi-service/pkg/service/keystore"
+	"github.com/tbd54566975/ssi-service/pkg/storage"
+)
+
+func testKeyStoreService(t *testing.T, db *storage.BoltDB) *keystore.Service {
+	serviceConfig := config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"}
+	// create a keystore service
+	keystoreService, err := keystore.NewKeyStoreService(serviceConfig, db)
+	require.NoError(t, err)
+	require.NotEmpty(t, keystoreService)
+	return keystoreService
+}
+
+func testCredentialService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service) *credential.Service {
+	serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}}
+	// create a credential service
+	credentialService, err := credential.NewCredentialService(serviceConfig, db, keyStore)
+	require.NoError(t, err)
+	require.NotEmpty(t, credentialService)
+	return credentialService
+}
diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go
index f2d367b..95eee28 100644
--- a/pkg/server/server_test.go
+++ b/pkg/server/server_test.go
@@ -4,9 +4,6 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"github.com/TBD54566975/ssi-sdk/credential/exchange"
-	"github.com/tbd54566975/ssi-service/pkg/service/dwn"
-
 	"io"
 	"net/http"
 	"net/http/httptest"
@@ -14,6 +11,10 @@ import (
 	"testing"
 	"time"
 
+	"github.com/TBD54566975/ssi-sdk/credential/exchange"
+
+	"github.com/tbd54566975/ssi-service/pkg/service/dwn"
+
 	credsdk "github.com/TBD54566975/ssi-sdk/credential"
 	manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
 	"github.com/TBD54566975/ssi-sdk/crypto"
@@ -61,7 +62,6 @@ func TestHealthCheckAPI(t *testing.T) {
 	assert.NoError(t, err)
 
 	assert.Equal(t, router.HealthOK, resp.Status)
-
 }
 
 func TestReadinessAPI(t *testing.T) {
@@ -104,7 +104,8 @@ func TestDIDAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		didService := newDIDService(tt, bolt)
+		_, keyStoreService := newKeyStore(tt, bolt)
+		didService := testDIDRouter(tt, bolt, keyStoreService)
 
 		// get DID methods
 		req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids", nil)
@@ -131,7 +132,8 @@ func TestDIDAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		didService := newDIDService(tt, bolt)
+		_, keyStoreService := newKeyStore(tt, bolt)
+		didService := testDIDRouter(tt, bolt, keyStoreService)
 
 		// create DID by method - key - missing body
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", nil)
@@ -179,7 +181,8 @@ func TestDIDAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		didService := newDIDService(tt, bolt)
+		_, keyStore := newKeyStore(tt, bolt)
+		didService := testDIDRouter(tt, bolt, keyStore)
 
 		// get DID by method
 		req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids/bad/worse", nil)
@@ -238,20 +241,6 @@ func TestDIDAPI(t *testing.T) {
 	})
 }
 
-func newDIDService(t *testing.T, bolt *storage.BoltDB) *router.DIDRouter {
-	serviceConfig := config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}}
-	didService, err := did.NewDIDService(serviceConfig, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, didService)
-
-	// create router for service
-	didRouter, err := router.NewDIDRouter(didService)
-	require.NoError(t, err)
-	require.NotEmpty(t, didRouter)
-
-	return didRouter
-}
-
 func TestSchemaAPI(t *testing.T) {
 	t.Run("Test Create Schema", func(tt *testing.T) {
 		bolt, err := storage.NewBoltDB()
@@ -262,7 +251,8 @@ func TestSchemaAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		schemaService := newSchemaService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		schemaService := testSchemaRouter(tt, bolt, keyStoreService)
 
 		simpleSchema := map[string]interface{}{
 			"type": "object",
@@ -309,7 +299,8 @@ func TestSchemaAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		schemaService := newSchemaService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		schemaService := testSchemaRouter(tt, bolt, keyStoreService)
 
 		// get schema that doesn't exist
 		w := httptest.NewRecorder()
@@ -395,19 +386,6 @@ func TestSchemaAPI(t *testing.T) {
 	})
 }
 
-func newSchemaService(t *testing.T, bolt *storage.BoltDB) *router.SchemaRouter {
-	schemaService, err := schema.NewSchemaService(config.SchemaServiceConfig{}, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, schemaService)
-
-	// create router for service
-	schemaRouter, err := router.NewSchemaRouter(schemaService)
-	require.NoError(t, err)
-	require.NotEmpty(t, schemaRouter)
-
-	return schemaRouter
-}
-
 func TestCredentialAPI(t *testing.T) {
 	t.Run("Test Create Credential", func(tt *testing.T) {
 		bolt, err := storage.NewBoltDB()
@@ -418,7 +396,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		// missing required field: data
 		badCredRequest := router.CreateCredentialRequest{
@@ -469,7 +448,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		w := httptest.NewRecorder()
 
@@ -530,7 +510,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		w := httptest.NewRecorder()
 
@@ -579,7 +560,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		w := httptest.NewRecorder()
 
@@ -627,7 +609,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		w := httptest.NewRecorder()
 
@@ -673,7 +656,8 @@ func TestCredentialAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		credService := newCredentialService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credService := testCredentialRouter(tt, bolt, keyStoreService)
 
 		createCredRequest := router.CreateCredentialRequest{
 			Issuer:  "did:abc:123",
@@ -724,19 +708,6 @@ func TestCredentialAPI(t *testing.T) {
 	})
 }
 
-func newCredentialService(t *testing.T, bolt *storage.BoltDB) *router.CredentialRouter {
-	credentialService, err := credential.NewCredentialService(config.CredentialServiceConfig{}, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, credentialService)
-
-	// create router for service
-	credentialRouter, err := router.NewCredentialRouter(credentialService)
-	require.NoError(t, err)
-	require.NotEmpty(t, credentialRouter)
-
-	return credentialRouter
-}
-
 func TestManifestAPI(t *testing.T) {
 	t.Run("Test Create Manifest", func(tt *testing.T) {
 		bolt, err := storage.NewBoltDB()
@@ -747,7 +718,9 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		// missing required field: Manifest
 		badManifestRequest := router.CreateManifestRequest{}
@@ -756,7 +729,7 @@ func TestManifestAPI(t *testing.T) {
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", badRequestValue)
 		w := httptest.NewRecorder()
 
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "invalid create manifest request")
 
@@ -768,7 +741,7 @@ func TestManifestAPI(t *testing.T) {
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -788,13 +761,15 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		w := httptest.NewRecorder()
 
 		// get a manifest that doesn't exit
 		req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/bad", nil)
-		err = manifestService.GetManifest(newRequestContext(), w, req)
+		err = manifestRouter.GetManifest(newRequestContext(), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "cannot get manifest without ID parameter")
 
@@ -803,7 +778,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get a manifest with an invalid id parameter
 		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/bad", nil)
-		err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": "bad"}), w, req)
+		err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": "bad"}), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "could not get manifest with id: bad")
 
@@ -815,7 +790,7 @@ func TestManifestAPI(t *testing.T) {
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -824,7 +799,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get manifest by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil)
-		err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
+		err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
 		assert.NoError(tt, err)
 
 		var getManifestResp router.GetManifestResponse
@@ -843,7 +818,9 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		w := httptest.NewRecorder()
 
@@ -852,7 +829,7 @@ func TestManifestAPI(t *testing.T) {
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -861,7 +838,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get manifest by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests"), nil)
-		err = manifestService.GetManifests(newRequestContext(), w, req)
+		err = manifestRouter.GetManifests(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var getManifestsResp router.GetManifestsResponse
@@ -881,7 +858,9 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		// good request
 		createManifestRequest := getValidManifestRequest()
@@ -889,7 +868,7 @@ func TestManifestAPI(t *testing.T) {
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
 		w := httptest.NewRecorder()
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -900,7 +879,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get credential by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil)
-		err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
+		err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
 		assert.NoError(tt, err)
 
 		var getManifestResp router.GetCredentialResponse
@@ -913,14 +892,14 @@ func TestManifestAPI(t *testing.T) {
 
 		// delete it
 		req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil)
-		err = manifestService.DeleteManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
+		err = manifestRouter.DeleteManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
 		assert.NoError(tt, err)
 
 		w.Flush()
 
 		// get it back
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil)
-		err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
+		err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), fmt.Sprintf("could not get manifest with id: %s", resp.Manifest.ID))
 	})
@@ -934,7 +913,9 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		// missing required field: Application
 		badManifestRequest := router.SubmitApplicationRequest{
@@ -945,7 +926,7 @@ func TestManifestAPI(t *testing.T) {
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", badRequestValue)
 		w := httptest.NewRecorder()
 
-		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "invalid submit application request")
 
@@ -957,7 +938,7 @@ func TestManifestAPI(t *testing.T) {
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -972,7 +953,7 @@ func TestManifestAPI(t *testing.T) {
 
 		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
-		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
 		var appResp router.SubmitApplicationResponse
 		err = json.NewDecoder(w.Body).Decode(&appResp)
@@ -992,13 +973,14 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
-
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 		w := httptest.NewRecorder()
 
 		// get a application that doesn't exit
 		req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications/bad", nil)
-		err = manifestService.GetApplication(newRequestContext(), w, req)
+		err = manifestRouter.GetApplication(newRequestContext(), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "cannot get application without ID parameter")
 
@@ -1010,7 +992,7 @@ func TestManifestAPI(t *testing.T) {
 
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -1022,7 +1004,7 @@ func TestManifestAPI(t *testing.T) {
 
 		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
-		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
 		var appResp router.SubmitApplicationResponse
 		err = json.NewDecoder(w.Body).Decode(&appResp)
@@ -1030,7 +1012,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get response by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/responses/%s", appResp.Response.ID), nil)
-		err = manifestService.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
+		err = manifestRouter.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
 		assert.NoError(tt, err)
 
 		var getResponseResponse router.GetResponseResponse
@@ -1041,7 +1023,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get all responses
 		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/responses", nil)
-		err = manifestService.GetResponses(newRequestContext(), w, req)
+		err = manifestRouter.GetResponses(newRequestContext(), w, req)
 
 		var getResponsesResp router.GetResponsesResponse
 		err = json.NewDecoder(w.Body).Decode(&getResponsesResp)
@@ -1052,7 +1034,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get all applications
 		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
-		err = manifestService.GetApplications(newRequestContext(), w, req)
+		err = manifestRouter.GetApplications(newRequestContext(), w, req)
 
 		var getApplicationsResp router.GetApplicationsResponse
 		err = json.NewDecoder(w.Body).Decode(&getApplicationsResp)
@@ -1063,7 +1045,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get application by id
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil)
-		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
+		err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
 		assert.NoError(tt, err)
 
 		var getApplicationResponse router.GetApplicationResponse
@@ -1082,7 +1064,9 @@ func TestManifestAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		// good manifest request
 		createManifestRequest := getValidManifestRequest()
@@ -1090,7 +1074,7 @@ func TestManifestAPI(t *testing.T) {
 		requestValue := newRequestValue(tt, createManifestRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue)
 		w := httptest.NewRecorder()
-		err = manifestService.CreateManifest(newRequestContext(), w, req)
+		err = manifestRouter.CreateManifest(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 
 		var resp router.CreateManifestResponse
@@ -1102,7 +1086,7 @@ func TestManifestAPI(t *testing.T) {
 
 		applicationRequestValue := newRequestValue(tt, createApplicationRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
-		err = manifestService.SubmitApplication(newRequestContext(), w, req)
+		err = manifestRouter.SubmitApplication(newRequestContext(), w, req)
 
 		var appResp router.SubmitApplicationResponse
 		err = json.NewDecoder(w.Body).Decode(&appResp)
@@ -1110,7 +1094,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get all applications
 		req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue)
-		err = manifestService.GetApplications(newRequestContext(), w, req)
+		err = manifestRouter.GetApplications(newRequestContext(), w, req)
 
 		var getApplicationsResp router.GetApplicationsResponse
 		err = json.NewDecoder(w.Body).Decode(&getApplicationsResp)
@@ -1121,7 +1105,7 @@ func TestManifestAPI(t *testing.T) {
 
 		// get the application
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil)
-		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
+		err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req)
 		assert.NoError(tt, err)
 
 		var getApplicationResp router.GetApplicationResponse
@@ -1132,32 +1116,19 @@ func TestManifestAPI(t *testing.T) {
 
 		// delete the application
 		req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationResp.Application.ID), nil)
-		err = manifestService.DeleteApplication(newRequestContextWithParams(map[string]string{"id": getApplicationResp.Application.ID}), w, req)
+		err = manifestRouter.DeleteApplication(newRequestContextWithParams(map[string]string{"id": getApplicationResp.Application.ID}), w, req)
 		assert.NoError(tt, err)
 
 		w.Flush()
 
 		// get it back
 		req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", appResp.Response.ID), nil)
-		err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
+		err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), fmt.Sprintf("could not get application with id: %s", appResp.Response.ID))
 	})
 }
 
-func newManifestService(t *testing.T, bolt *storage.BoltDB) *router.ManifestRouter {
-	manifestService, err := manifest.NewManifestService(config.ManifestServiceConfig{}, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, manifestService)
-
-	// create router for service
-	manifestRouter, err := router.NewManifestRouter(manifestService)
-	require.NoError(t, err)
-	require.NotEmpty(t, manifestRouter)
-
-	return manifestRouter
-}
-
 func TestDWNAPI(t *testing.T) {
 	t.Run("Test DWN Publish Manifest", func(tt *testing.T) {
 		bolt, err := storage.NewBoltDB()
@@ -1168,9 +1139,10 @@ func TestDWNAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		dwnService := newDWNService(tt, bolt)
-
-		manifestService := newManifestService(tt, bolt)
+		keyStoreService := testKeyStoreService(tt, bolt)
+		dwnService := testDWNRouter(tt, bolt, keyStoreService)
+		credentialService := testCredentialService(tt, bolt, keyStoreService)
+		manifestService := testManifestRouter(tt, bolt, keyStoreService, credentialService)
 
 		w := httptest.NewRecorder()
 
@@ -1197,18 +1169,6 @@ func TestDWNAPI(t *testing.T) {
 		assert.ErrorContains(tt, err, "unsupported protocol scheme")
 	})
 }
-func newDWNService(t *testing.T, bolt *storage.BoltDB) *router.DWNRouter {
-	dwnService, err := dwn.NewDWNService(config.DWNServiceConfig{DWNEndpoint: "test-endpoint"}, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, dwnService)
-
-	// create router for service
-	dwnRouter, err := router.NewDWNRouter(dwnService)
-	require.NoError(t, err)
-	require.NotEmpty(t, dwnRouter)
-
-	return dwnRouter
-}
 
 func TestKeyStoreAPI(t *testing.T) {
 	t.Run("Test Store Key", func(tt *testing.T) {
@@ -1220,7 +1180,7 @@ func TestKeyStoreAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		keyStoreService := newKeyStoreService(tt, bolt)
+		keyStoreRouter, _ := newKeyStore(tt, bolt)
 		w := httptest.NewRecorder()
 
 		// bad key type
@@ -1232,7 +1192,7 @@ func TestKeyStoreAPI(t *testing.T) {
 		}
 		badRequestValue := newRequestValue(tt, badKeyStoreRequest)
 		req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", badRequestValue)
-		err = keyStoreService.StoreKey(newRequestContext(), w, req)
+		err = keyStoreRouter.StoreKey(newRequestContext(), w, req)
 		assert.Error(tt, err)
 		assert.Contains(tt, err.Error(), "could not store key: test-kid, unsupported key type: bad")
 
@@ -1256,7 +1216,7 @@ func TestKeyStoreAPI(t *testing.T) {
 		}
 		requestValue := newRequestValue(tt, storeKeyRequest)
 		req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", requestValue)
-		err = keyStoreService.StoreKey(newRequestContext(), w, req)
+		err = keyStoreRouter.StoreKey(newRequestContext(), w, req)
 		assert.NoError(tt, err)
 	})
 
@@ -1269,7 +1229,7 @@ func TestKeyStoreAPI(t *testing.T) {
 			_ = os.Remove(storage.DBFile)
 		})
 
-		keyStoreService := newKeyStoreService(tt, bolt)
+		keyStoreService, _ := newKeyStore(tt, bolt)
 		w := httptest.NewRecorder()
 
 		// store a valid key
@@ -1309,20 +1269,6 @@ func TestKeyStoreAPI(t *testing.T) {
 	})
 }
 
-func newKeyStoreService(t *testing.T, bolt *storage.BoltDB) *router.KeyStoreRouter {
-	serviceConfig := config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"}
-	keyStoreService, err := keystore.NewKeyStoreService(serviceConfig, bolt)
-	require.NoError(t, err)
-	require.NotEmpty(t, keyStoreService)
-
-	// create router for service
-	keyStoreRouter, err := router.NewKeyStoreRouter(keyStoreService)
-	require.NoError(t, err)
-	require.NotEmpty(t, keyStoreRouter)
-
-	return keyStoreRouter
-}
-
 func newRequestValue(t *testing.T, data interface{}) io.Reader {
 	dataBytes, err := json.Marshal(data)
 	require.NoError(t, err)
@@ -1393,7 +1339,6 @@ func getValidManifestRequest() manifest.CreateManifestRequest {
 }
 
 func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest {
-
 	createApplication := manifestsdk.CredentialApplication{
 		ID:          uuid.New().String(),
 		SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/",
@@ -1421,3 +1366,121 @@ func getValidApplicationRequest(manifestID string, submissionDescriptorId string
 
 	return createApplicationRequest
 }
+
+func newKeyStore(t *testing.T, bolt *storage.BoltDB) (*router.KeyStoreRouter, *keystore.Service) {
+	keyStoreService := testKeyStoreService(t, bolt)
+
+	// create router for service
+	keyStoreRouter, err := router.NewKeyStoreRouter(keyStoreService)
+	require.NoError(t, err)
+	require.NotEmpty(t, keyStoreRouter)
+
+	return keyStoreRouter, keyStoreService
+}
+
+func testKeyStoreService(t *testing.T, db *storage.BoltDB) *keystore.Service {
+	serviceConfig := config.KeyStoreServiceConfig{
+		BaseServiceConfig:  &config.BaseServiceConfig{Name: "test-keystore"},
+		ServiceKeyPassword: "test-password",
+	}
+
+	// create a keystore service
+	keystoreService, err := keystore.NewKeyStoreService(serviceConfig, db)
+	require.NoError(t, err)
+	require.NotEmpty(t, keystoreService)
+	return keystoreService
+}
+
+func testDIDService(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *did.Service {
+	serviceConfig := config.DIDServiceConfig{
+		BaseServiceConfig: &config.BaseServiceConfig{Name: "test-did"},
+		Methods:           []string{"key"},
+	}
+
+	// create a did service
+	didService, err := did.NewDIDService(serviceConfig, bolt, keyStore)
+	require.NoError(t, err)
+	require.NotEmpty(t, didService)
+	return didService
+}
+
+func testDIDRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.DIDRouter {
+	didService := testDIDService(t, bolt, keyStore)
+
+	// create router for service
+	didRouter, err := router.NewDIDRouter(didService)
+	require.NoError(t, err)
+	require.NotEmpty(t, didRouter)
+	return didRouter
+}
+
+func testSchemaService(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *schema.Service {
+	schemaService, err := schema.NewSchemaService(config.SchemaServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "test-schema"}}, bolt, keyStore)
+	require.NoError(t, err)
+	require.NotEmpty(t, schemaService)
+	return schemaService
+}
+
+func testSchemaRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.SchemaRouter {
+	schemaService := testSchemaService(t, bolt, keyStore)
+
+	// create router for service
+	schemaRouter, err := router.NewSchemaRouter(schemaService)
+	require.NoError(t, err)
+	require.NotEmpty(t, schemaRouter)
+	return schemaRouter
+}
+
+func testCredentialService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service) *credential.Service {
+	serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}}
+
+	// create a credential service
+	credentialService, err := credential.NewCredentialService(serviceConfig, db, keyStore)
+	require.NoError(t, err)
+	require.NotEmpty(t, credentialService)
+	return credentialService
+}
+
+func testCredentialRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.CredentialRouter {
+	credentialService := testCredentialService(t, bolt, keyStore)
+
+	// create router for service
+	credentialRouter, err := router.NewCredentialRouter(credentialService)
+	require.NoError(t, err)
+	require.NotEmpty(t, credentialRouter)
+
+	return credentialRouter
+}
+
+func testManifestService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service, credential *credential.Service) *manifest.Service {
+	serviceConfig := config.ManifestServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "manifest"}}
+	// create a manifest service
+	manifestService, err := manifest.NewManifestService(serviceConfig, db, keyStore, credential)
+	require.NoError(t, err)
+	require.NotEmpty(t, manifestService)
+	return manifestService
+}
+
+func testManifestRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service, credential *credential.Service) *router.ManifestRouter {
+	manifestService := testManifestService(t, bolt, keyStore, credential)
+
+	// create router for service
+	manifestRouter, err := router.NewManifestRouter(manifestService)
+	require.NoError(t, err)
+	require.NotEmpty(t, manifestRouter)
+
+	return manifestRouter
+}
+
+func testDWNRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.DWNRouter {
+	dwnService, err := dwn.NewDWNService(config.DWNServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "test-dwn"}, DWNEndpoint: "test-endpoint"}, bolt, keyStore)
+	require.NoError(t, err)
+	require.NotEmpty(t, dwnService)
+
+	// create router for service
+	dwnRouter, err := router.NewDWNRouter(dwnService)
+	require.NoError(t, err)
+	require.NotEmpty(t, dwnRouter)
+
+	return dwnRouter
+}