diff --git a/cmd/signer/main.go b/cmd/signer/main.go index d93f8675d181af5c26a0a356c8214e675bdffc4c..a03d78e2cb806b63a2e65ece33a3084d9df241f1 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -61,7 +61,7 @@ func main() { healthSvc goahealth.Service ) { - signerSvc = signer.New(vault, cfg.Vault.DefaultKey, httpClient, logger) + signerSvc = signer.New(vault, cfg.Credentials.Issuer, cfg.Vault.DefaultKey, cfg.Vault.SupportedKeys, httpClient, logger) healthSvc = health.New() } diff --git a/design/design.go b/design/design.go index cbba82903578276998fad75e7ed7ab8bf54597e4..6b9e934829d6de9e53358587b15e1936c6ac5e24 100644 --- a/design/design.go +++ b/design/design.go @@ -47,7 +47,7 @@ var _ = Service("signer", func() { Method("GetKey", func() { Description("GetKey returns key information from Vault or OCM.") Payload(GetKeyRequest) - Result(Any) + Result(Any, "Public Key represented as DID Verification Method.") HTTP(func() { GET("/v1/keys/{key}") diff --git a/gen/http/openapi3.json b/gen/http/openapi3.json index 8252c78508ef777bdbce49edf61142f9e337c7ad..59bb6e93d738269c6c734ecf2a9336622a16eefb 100644 --- a/gen/http/openapi3.json +++ b/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":"1.0"},"servers":[{"url":"http://localhost:8085","description":"Signer Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Credential in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Credential in JSON format.","example":"RGVsZW5pdGkgaXBzYS4=","format":"binary"},"example":"RW5pbSBkZXNlcnVudC4="}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Itaque adipisci voluptas.","format":"binary"},"example":"Cupiditate et aliquid reiciendis pariatur."}}}}}},"/v1/keys/{key}":{"get":{"tags":["signer"],"summary":"GetKey signer","description":"GetKey returns key information from Vault or OCM.","operationId":"signer#GetKey","parameters":[{"name":"key","in":"path","description":"Name of requested key.","required":true,"schema":{"type":"string","description":"Name of requested key.","example":"key1"},"example":"key1"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Laudantium exercitationem quis sunt eos.","format":"binary"},"example":"Eum molestiae."}}}}}},"/v1/presentation/proof":{"post":{"tags":["signer"],"summary":"PresentationProof signer","description":"PresentationProof adds a proof to a given Verifiable Presentation.","operationId":"signer#PresentationProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Presentation in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Presentation in JSON format.","example":"QXNwZXJpb3JlcyBtb2xlc3RpYXMgcXVpLg==","format":"binary"},"example":"TW9sZXN0aWFlIHZlbGl0IG1haW9yZXMgZXQgcXVpYS4="}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Ipsa vel in repudiandae repellat.","format":"binary"},"example":"Voluptatem consectetur."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"signer","description":"Sign service provides endpoints for making digital signatures and proofs for verifiable credentials and presentations."}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Signer Service","description":"The signer service exposes HTTP API for creating and verifying digital signatures.","version":"1.0"},"servers":[{"url":"http://localhost:8085","description":"Signer Server"}],"paths":{"/liveness":{"get":{"tags":["health"],"summary":"Liveness health","operationId":"health#Liveness","responses":{"200":{"description":"OK response."}}}},"/readiness":{"get":{"tags":["health"],"summary":"Readiness health","operationId":"health#Readiness","responses":{"200":{"description":"OK response."}}}},"/v1/credential/proof":{"post":{"tags":["signer"],"summary":"CredentialProof signer","description":"CredentialProof adds a proof to a given Verifiable Credential.","operationId":"signer#CredentialProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Credential in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Credential in JSON format.","example":"RGVsZW5pdGkgaXBzYS4=","format":"binary"},"example":"RW5pbSBkZXNlcnVudC4="}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Itaque adipisci voluptas.","format":"binary"},"example":"Cupiditate et aliquid reiciendis pariatur."}}}}}},"/v1/keys/{key}":{"get":{"tags":["signer"],"summary":"GetKey signer","description":"GetKey returns key information from Vault or OCM.","operationId":"signer#GetKey","parameters":[{"name":"key","in":"path","description":"Name of requested key.","required":true,"schema":{"type":"string","description":"Name of requested key.","example":"key1"},"example":"key1"}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","description":"Public Key represented as DID Verification Method.","example":"Laudantium exercitationem quis sunt eos.","format":"binary"},"example":"Eum molestiae."}}}}}},"/v1/presentation/proof":{"post":{"tags":["signer"],"summary":"PresentationProof signer","description":"PresentationProof adds a proof to a given Verifiable Presentation.","operationId":"signer#PresentationProof","parameters":[{"name":"key","in":"query","description":"Key to use for the proof signature (optional).","allowEmptyValue":true,"schema":{"type":"string","description":"Key to use for the proof signature (optional).","example":"key1"},"example":"key1"}],"requestBody":{"description":"Verifiable Presentation in JSON format.","required":true,"content":{"application/json":{"schema":{"type":"string","description":"Verifiable Presentation in JSON format.","example":"QXNwZXJpb3JlcyBtb2xlc3RpYXMgcXVpLg==","format":"binary"},"example":"TW9sZXN0aWFlIHZlbGl0IG1haW9yZXMgZXQgcXVpYS4="}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Ipsa vel in repudiandae repellat.","format":"binary"},"example":"Voluptatem consectetur."}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service provides health check endpoints."},{"name":"signer","description":"Sign service provides endpoints for making digital signatures and proofs for verifiable credentials and presentations."}]} \ No newline at end of file diff --git a/gen/http/openapi3.yaml b/gen/http/openapi3.yaml index a0b57111324702aa270e67a22ab4d4e41ce1d5bf..d131c6a2f7995be04d111a659c2d18158fe84e33 100644 --- a/gen/http/openapi3.yaml +++ b/gen/http/openapi3.yaml @@ -115,6 +115,7 @@ paths: application/json: schema: type: string + description: Public Key represented as DID Verification Method. example: Laudantium exercitationem quis sunt eos. format: binary example: Eum molestiae. diff --git a/go.mod b/go.mod index 0fe2cd0208b073ab70019b70b46be5be831e0bd9..698ec0ef7d86777383b262c1cebe3a94c8c9a57e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/hyperledger/aries-framework-go v0.1.8 github.com/kelseyhightower/envconfig v1.4.0 github.com/piprate/json-gold v0.4.1-0.20210813112359-33b90c4ca86c + github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.21.0 goa.design/goa/v3 v3.7.6 @@ -52,7 +53,6 @@ require ( github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/smartystreets/assertions v1.13.0 // indirect - github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 // indirect github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/internal/clients/vault/client.go b/internal/clients/vault/client.go index bf2b160f18c56426b90619508ab33903c6710f11..0c41523070afee4980d8243f7588c06fd42ec112 100644 --- a/internal/clients/vault/client.go +++ b/internal/clients/vault/client.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" vaultpkg "github.com/hashicorp/vault/api" @@ -51,7 +52,7 @@ func New(addr string, token string, probe bool, httpClient *http.Client) (*Clien // WithKey must be called before calling Sign on the client, as each // request might be used with a different signing key. This function // will make a new Client wrapper with just the key being different. -func (c *Client) WithKey(key string) signer.Signer { +func (c *Client) WithKey(key string) signer.Vault { return &Client{ signkey: key, client: c.client, @@ -59,20 +60,20 @@ func (c *Client) WithKey(key string) signer.Signer { } // Key tries to fetch a key with the given name from the Vault. -func (c *Client) Key(ctx context.Context, key string) (*signer.SignKey, error) { +func (c *Client) Key(ctx context.Context, key string) (*signer.VaultKey, error) { req := c.client.NewRequest(http.MethodGet, pathKeys+key) - res, err := c.client.RawRequestWithContext(ctx, req) + resp, err := c.client.RawRequestWithContext(ctx, req) if err != nil { - return nil, errors.New(errors.GetKind(res.StatusCode), err) + return nil, errors.New(errors.GetKind(resp.StatusCode), err) } - defer res.Body.Close() + defer resp.Body.Close() var response getKeyResponse - if err := json.NewDecoder(res.Body).Decode(&response); err != nil { + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } - return &signer.SignKey{ + return &signer.VaultKey{ Name: response.Data.Name, Type: response.Data.Type, PublicKey: response.lastPublicKeyVersion(), @@ -92,11 +93,11 @@ func (c *Client) Sign(data []byte) ([]byte, error) { return nil, err } - res, err := c.client.RawRequest(req) + resp, err := c.client.RawRequest(req) if err != nil { - return nil, errors.New(errors.GetKind(res.StatusCode), err) + return nil, errors.New(errors.GetKind(resp.StatusCode), err) } - defer res.Body.Close() + defer resp.Body.Close() // expected response from the sign operation var response struct { @@ -104,7 +105,7 @@ func (c *Client) Sign(data []byte) ([]byte, error) { Signature string `json:"signature"` } `json:"data"` } - if err := json.NewDecoder(res.Body).Decode(&response); err != nil { + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } @@ -112,5 +113,16 @@ func (c *Client) Sign(data []byte) ([]byte, error) { return nil, fmt.Errorf("unexpected response: no signature") } - return []byte(response.Data.Signature), nil + // strip the vault specific prefix from the signature, e.g. vault:v1:xxx -> xxx + // because verifiers are not going to use our Vault for verification, but must + // verify the "pure" signature on their own. + var signature string + s := strings.Split(response.Data.Signature, ":") + if len(s) > 1 { + signature = s[len(s)-1] + } else { + signature = s[0] + } + + return base64.StdEncoding.DecodeString(signature) } diff --git a/internal/clients/vault/client_test.go b/internal/clients/vault/client_test.go index d0fc41e473dab450c53000374c766dd1810777bf..6bad834b69415ea3a15e4ef2f46a1da9dd56b65e 100644 --- a/internal/clients/vault/client_test.go +++ b/internal/clients/vault/client_test.go @@ -19,7 +19,7 @@ func TestClient_Key(t *testing.T) { key string handler http.HandlerFunc - result *signer.SignKey + result *signer.VaultKey errkind errors.Kind errtext string }{ @@ -56,7 +56,7 @@ func TestClient_Key(t *testing.T) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(`{"data":{"name":"key123","type":"ed25519"}}`)) }, - result: &signer.SignKey{ + result: &signer.VaultKey{ Name: "key123", Type: "ed25519", }, @@ -139,7 +139,7 @@ func TestClient_Sign(t *testing.T) { name: "successful signing", handler: func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(`{"data":{"signature":"hello"}}`)) + _, _ = w.Write([]byte(`{"data":{"signature":"aGVsbG8="}}`)) }, result: []byte("hello"), }, diff --git a/internal/config/config.go b/internal/config/config.go index 731dc94613c989fa2a65f770b8f751f4afd57e37..34a15f783e8f6b7f335446a310bd49e3ab268b46 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,8 +3,9 @@ package config import "time" type Config struct { - HTTP httpConfig - Vault vaultConfig + HTTP httpConfig + Vault vaultConfig + Credentials credentialConfig LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"` } @@ -18,7 +19,12 @@ type httpConfig struct { } type vaultConfig struct { - Addr string `envconfig:"VAULT_ADDR" required:"true"` - Token string `envconfig:"VAULT_TOKEN" required:"true"` - DefaultKey string `envconfig:"VAULT_SIGNING_KEY" required:"true"` + Addr string `envconfig:"VAULT_ADDR" required:"true"` + Token string `envconfig:"VAULT_TOKEN" required:"true"` + DefaultKey string `envconfig:"VAULT_SIGNING_KEY" required:"true"` + SupportedKeys []string `envconfig:"VAULT_SUPPORTED_KEYS" required:"true"` +} + +type credentialConfig struct { + Issuer string `envconfig:"CREDENTIAL_ISSUER" required:"true"` } diff --git a/internal/service/signer/service.go b/internal/service/signer/service.go index 6e19f0b1b22b1efb3a4fc9f89b4cdf2ffdb3777c..b813939a3c6796d5cc55b726a273e66755cb7ffa 100644 --- a/internal/service/signer/service.go +++ b/internal/service/signer/service.go @@ -2,62 +2,96 @@ package signer import ( "context" + "crypto/ed25519" + "crypto/x509" + "encoding/pem" "fmt" "net/http" "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" ariesigner "github.com/hyperledger/aries-framework-go/pkg/doc/signature/signer" "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite" - "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ecdsasecp256k1signature2019" - "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2018" + "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/jsonwebsignature2020" "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "github.com/piprate/json-gold/ld" + "github.com/square/go-jose/v3" "go.uber.org/zap" "code.vereign.com/gaiax/tsa/golib/errors" "code.vereign.com/gaiax/tsa/signer/gen/signer" ) -//go:generate counterfeiter . Signer +//go:generate counterfeiter . Vault -type SignKey struct { +type VerificationMethod struct { + ID string `json:"id"` + Type string `json:"type"` + PublicKeyJWK *jose.JSONWebKey `json:"publicKeyJWK"` +} + +type VaultKey struct { Name string `json:"name"` Type string `json:"type"` PublicKey string `json:"public_key,omitempty"` } -type Signer interface { - Key(ctx context.Context, key string) (*SignKey, error) +type Vault interface { + Key(ctx context.Context, key string) (*VaultKey, error) Sign(data []byte) ([]byte, error) - WithKey(key string) Signer + WithKey(key string) Vault } type Service struct { - signer Signer - defaultKey string - docLoader *ld.CachingDocumentLoader - logger *zap.Logger + vault Vault + issuer string + defaultKey string + supportedKeys []string // supported key types + docLoader *ld.CachingDocumentLoader + logger *zap.Logger } -func New(signer Signer, defaultKey string, httpClient *http.Client, logger *zap.Logger) *Service { +func New(vault Vault, issuer string, defaultKey string, supportedKeys []string, httpClient *http.Client, logger *zap.Logger) *Service { loader := ld.NewDefaultDocumentLoader(httpClient) return &Service{ - signer: signer, - defaultKey: defaultKey, - docLoader: ld.NewCachingDocumentLoader(loader), - logger: logger, + vault: vault, + issuer: issuer, + defaultKey: defaultKey, + supportedKeys: supportedKeys, + docLoader: ld.NewCachingDocumentLoader(loader), + logger: logger, } } // GetKey returns a key from Vault or OCM. func (s *Service) GetKey(ctx context.Context, req *signer.GetKeyRequest) (interface{}, error) { - key, err := s.signer.Key(ctx, req.Key) + logger := s.logger.With(zap.String("operation", "getKey")) + + key, err := s.vault.Key(ctx, req.Key) if err != nil { - s.logger.Error("error getting key", zap.Error(err)) + logger.Error("error getting key", zap.Error(err)) return nil, err } - return key, nil + if !s.supportedKey(key.Type) { + logger.Error("unsupported key type", zap.String("key", req.Key), zap.String("keyType", key.Type)) + return nil, fmt.Errorf("unsupported key type: %s", key.Type) + } + + pubKey, err := s.jwkFromKey(key) + if err != nil { + logger.Error("error making JWK from Vault key", + zap.String("key", req.Key), + zap.String("keyType", key.Type), + zap.Error(err), + ) + return nil, fmt.Errorf("error converting vault key to JWK") + } + + return &VerificationMethod{ + ID: req.Key, + Type: "JsonWebKey2020", + PublicKeyJWK: pubKey, + }, nil } // CredentialProof adds a proof to a given Verifiable Credential. @@ -75,13 +109,18 @@ func (s *Service) CredentialProof(ctx context.Context, req *signer.CredentialPro keyname = *req.Key } - key, err := s.signer.Key(ctx, keyname) + key, err := s.vault.Key(ctx, keyname) if err != nil { logger.Error("error getting signing key", zap.String("key", keyname), zap.Error(err)) return nil, errors.New("error getting signing key", err) } - proofContext, err := s.proofContext(key.Name, key.Type) + if !s.supportedKey(key.Type) { + logger.Error("unsupported key type", zap.String("key", keyname), zap.String("keyType", key.Type)) + return nil, fmt.Errorf("unsupported key type: %s", key.Type) + } + + proofContext, err := s.proofContext(key.Name) if err != nil { logger.Error("error building proof context", zap.Error(err)) return nil, err @@ -110,13 +149,18 @@ func (s *Service) PresentationProof(ctx context.Context, req *signer.Presentatio keyname = *req.Key } - key, err := s.signer.Key(ctx, keyname) + key, err := s.vault.Key(ctx, keyname) if err != nil { logger.Error("error getting signing key", zap.String("key", keyname), zap.Error(err)) return nil, errors.New("error getting signing key", err) } - proofContext, err := s.proofContext(key.Name, key.Type) + if !s.supportedKey(key.Type) { + logger.Error("unsupported key type", zap.String("key", keyname), zap.String("keyType", key.Type)) + return nil, fmt.Errorf("unsupported key type: %s", key.Type) + } + + proofContext, err := s.proofContext(key.Name) if err != nil { logger.Error("error building proof context", zap.Error(err)) return nil, err @@ -131,8 +175,8 @@ func (s *Service) PresentationProof(ctx context.Context, req *signer.Presentatio } // proofContext is used to create proofs. -func (s *Service) proofContext(key string, keyType string) (*verifiable.LinkedDataProofContext, error) { - sigSuite, sigType, err := s.signatureSuite(key, keyType) +func (s *Service) proofContext(key string) (*verifiable.LinkedDataProofContext, error) { + sigSuite, sigType, err := s.signatureSuite(key) if err != nil { return nil, err } @@ -140,33 +184,53 @@ func (s *Service) proofContext(key string, keyType string) (*verifiable.LinkedDa proofContext := &verifiable.LinkedDataProofContext{ Suite: sigSuite, SignatureType: sigType, - SignatureRepresentation: verifiable.SignatureProofValue, - VerificationMethod: key, + SignatureRepresentation: verifiable.SignatureJWS, + VerificationMethod: s.issuer + "#" + key, } return proofContext, nil } // signatureSuite is used to create digital signatures on proofs. -func (s *Service) signatureSuite(key string, keyType string) (sigSuite ariesigner.SignatureSuite, sigType string, err error) { - signer := s.signer.WithKey(key) +func (s *Service) signatureSuite(key string) (sigSuite ariesigner.SignatureSuite, sigType string, err error) { + signer := s.vault.WithKey(key) + sigType = "JsonWebSignature2020" + sigSuite = jsonwebsignature2020.New(suite.WithSigner(signer)) - switch keyType { - case "ed25519": - sigType = ed25519signature2018.SignatureType - sigSuite = ed25519signature2018.New( - suite.WithSigner(signer), - suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier())) + return sigSuite, sigType, nil +} + +func (s *Service) supportedKey(keyType string) bool { + for _, kt := range s.supportedKeys { + if kt == keyType { + return true + } + } + return false +} - case "ecdsa-p256": - sigType = "EcdsaSecp256k1Signature2019" - sigSuite = ecdsasecp256k1signature2019.New( - suite.WithSigner(signer), - suite.WithVerifier(ecdsasecp256k1signature2019.NewPublicKeyVerifier())) +func (s *Service) jwkFromKey(key *VaultKey) (*jose.JSONWebKey, error) { + k := &jose.JSONWebKey{ + KeyID: key.Name, + } + switch key.Type { + case "ed25519": + k.Key = ed25519.PublicKey(key.PublicKey) + case "ecdsa-p256", "ecdsa-p384", "ecdsa-p521", "rsa-2048": + block, _ := pem.Decode([]byte(key.PublicKey)) + if block == nil { + return nil, fmt.Errorf("no public key found during PEM decode") + } + + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + k.Key = pub default: - return nil, "", fmt.Errorf("unsupported key type: %q", keyType) + return nil, fmt.Errorf("unsupported key type: %s", key.Type) } - return sigSuite, sigType, nil + return k, nil } diff --git a/internal/service/signer/service_test.go b/internal/service/signer/service_test.go index 3c34e982648ec97a1086d226415b7d234e130931..09b31f33a532c7ad64e999f1d704f7bde63e86f9 100644 --- a/internal/service/signer/service_test.go +++ b/internal/service/signer/service_test.go @@ -2,6 +2,7 @@ package signer_test import ( "context" + "crypto/ecdsa" "encoding/base64" "net/http" "testing" @@ -19,13 +20,13 @@ import ( func TestService_GetKey(t *testing.T) { t.Run("signer returns error when getting key", func(t *testing.T) { - signerError := &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + vaultError := &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.NotFound, "key not found") }, } - svc := signer.New(signerError, "default key", http.DefaultClient, zap.NewNop()) + svc := signer.New(vaultError, "issuer", "default key", []string{}, http.DefaultClient, zap.NewNop()) result, err := svc.GetKey(context.Background(), &goasigner.GetKeyRequest{Key: "key1"}) assert.Nil(t, result) assert.Error(t, err) @@ -34,35 +35,40 @@ func TestService_GetKey(t *testing.T) { assert.Equal(t, errors.NotFound, e.Kind) }) - t.Run("signer returns key successfully", func(t *testing.T) { - signerOK := &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ - Name: "keyname", - Type: "ed25519", - PublicKey: "public key", + t.Run("signer returns ecdsa-p256 key successfully", func(t *testing.T) { + signerOK := &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ + Name: "key1", + Type: "ecdsa-p256", + PublicKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERTx/2cyYcGVSIRP/826S32BiZxSg\nnzyXgRYmKP8N2l26ec/MwCdsHIEyraX1ZYqwMUT4wO9fqFiGsRKyMBpPnQ==\n-----END PUBLIC KEY-----\n", }, nil }, } - svc := signer.New(signerOK, "default key", http.DefaultClient, zap.NewNop()) + svc := signer.New(signerOK, "issuer", "default key", []string{"ecdsa-p256"}, http.DefaultClient, zap.NewNop()) result, err := svc.GetKey(context.Background(), &goasigner.GetKeyRequest{Key: "key1"}) assert.NotNil(t, result) assert.NoError(t, err) - assert.Equal(t, &signer.SignKey{ - Name: "keyname", - Type: "ed25519", - PublicKey: "public key", - }, result) + + verMethod, ok := result.(*signer.VerificationMethod) + assert.True(t, ok) + + assert.Equal(t, "key1", verMethod.ID) + assert.Equal(t, "JsonWebKey2020", verMethod.Type) + assert.NotNil(t, verMethod.PublicKeyJWK) + assert.NotNil(t, verMethod.PublicKeyJWK.Key) + assert.IsType(t, verMethod.PublicKeyJWK.Key, (*ecdsa.PublicKey)(nil)) }) } func TestService_CredentialProof(t *testing.T) { tests := []struct { - name string - signer *signerfakes.FakeSigner - defaultKey string - req *goasigner.CredentialProofRequest + name string + signer *signerfakes.FakeVault + defaultKey string + supportedKeys []string + req *goasigner.CredentialProofRequest errkind errors.Kind errtext string @@ -72,7 +78,6 @@ func TestService_CredentialProof(t *testing.T) { subject []verifiable.Subject issuer verifiable.Issuer proofPurpose string - proofValue string proofType string proofVerificationMethod string }{ @@ -107,8 +112,8 @@ func TestService_CredentialProof(t *testing.T) { Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.NotFound) }, }, @@ -122,8 +127,8 @@ func TestService_CredentialProof(t *testing.T) { Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.Internal) }, }, @@ -137,8 +142,8 @@ func TestService_CredentialProof(t *testing.T) { Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.Internal) }, }, @@ -152,9 +157,9 @@ func TestService_CredentialProof(t *testing.T) { Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key23", Type: "rsa4096", }, nil @@ -164,21 +169,22 @@ func TestService_CredentialProof(t *testing.T) { errtext: "unsupported key type", }, { - name: "valid credential and signer key type ed25519", - defaultKey: "key1", + name: "valid credential and signer key type ed25519", + defaultKey: "key1", + supportedKeys: []string{"ed25519"}, req: &goasigner.CredentialProofRequest{ Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key123", Type: "ed25519", }, nil }, - WithKeyStub: func(key string) signer.Signer { - return &signerfakes.FakeSigner{ + WithKeyStub: func(key string) signer.Vault { + return &signerfakes.FakeVault{ SignStub: func(data []byte) ([]byte, error) { return []byte("test signature"), nil }, @@ -192,28 +198,28 @@ func TestService_CredentialProof(t *testing.T) { issuer: verifiable.Issuer{ID: "https://example.com"}, types: []string{verifiable.VCType}, proofPurpose: "assertionMethod", - proofType: "Ed25519Signature2018", - proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), - proofVerificationMethod: "key123", + proofType: "JsonWebSignature2020", + proofVerificationMethod: "issuer#key123", }, { - name: "valid credential and signer key type ecdsa-p256", - defaultKey: "key1", + name: "valid credential and signer key type ecdsa-p256", + defaultKey: "key1", + supportedKeys: []string{"ecdsa-p256"}, req: &goasigner.CredentialProofRequest{ Key: ptr.String("key2"), Credential: []byte(validCredential), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key123", Type: "ecdsa-p256", }, nil }, - WithKeyStub: func(key string) signer.Signer { - return &signerfakes.FakeSigner{ + WithKeyStub: func(key string) signer.Vault { + return &signerfakes.FakeVault{ SignStub: func(data []byte) ([]byte, error) { - return []byte("test signature"), nil + return base64.StdEncoding.DecodeString("aGVsbG8=") }, } }, @@ -225,15 +231,14 @@ func TestService_CredentialProof(t *testing.T) { issuer: verifiable.Issuer{ID: "https://example.com"}, types: []string{verifiable.VCType}, proofPurpose: "assertionMethod", - proofType: "EcdsaSecp256k1Signature2019", - proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), - proofVerificationMethod: "key123", + proofType: "JsonWebSignature2020", + proofVerificationMethod: "issuer#key123", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - svc := signer.New(test.signer, test.defaultKey, http.DefaultClient, zap.NewNop()) + svc := signer.New(test.signer, "issuer", test.defaultKey, test.supportedKeys, http.DefaultClient, zap.NewNop()) res, err := svc.CredentialProof(context.Background(), test.req) if err != nil { assert.Nil(t, res) @@ -257,8 +262,8 @@ func TestService_CredentialProof(t *testing.T) { assert.Equal(t, test.types, vc.Types) assert.Equal(t, test.proofPurpose, vc.Proofs[0]["proofPurpose"]) assert.Equal(t, test.proofType, vc.Proofs[0]["type"]) - assert.Equal(t, test.proofValue, vc.Proofs[0]["proofValue"]) assert.Equal(t, test.proofVerificationMethod, vc.Proofs[0]["verificationMethod"]) + assert.NotEmpty(t, vc.Proofs[0]["jws"]) } }) } @@ -266,10 +271,11 @@ func TestService_CredentialProof(t *testing.T) { func TestService_PresentationProof(t *testing.T) { tests := []struct { - name string - signer *signerfakes.FakeSigner - defaultKey string - req *goasigner.PresentationProofRequest + name string + signer *signerfakes.FakeVault + defaultKey string + supportedKeys []string + req *goasigner.PresentationProofRequest errkind errors.Kind errtext string @@ -277,7 +283,6 @@ func TestService_PresentationProof(t *testing.T) { contexts []string types []string proofPurpose string - proofValue string proofType string proofVerificationMethod string }{ @@ -312,8 +317,8 @@ func TestService_PresentationProof(t *testing.T) { Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.NotFound) }, }, @@ -327,8 +332,8 @@ func TestService_PresentationProof(t *testing.T) { Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.Internal) }, }, @@ -342,8 +347,8 @@ func TestService_PresentationProof(t *testing.T) { Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { return nil, errors.New(errors.Internal) }, }, @@ -357,9 +362,9 @@ func TestService_PresentationProof(t *testing.T) { Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key23", Type: "rsa4096", }, nil @@ -369,21 +374,22 @@ func TestService_PresentationProof(t *testing.T) { errtext: "unsupported key type", }, { - name: "valid presentation and signer key type ed25519", - defaultKey: "key1", + name: "valid presentation and signer key type ed25519", + defaultKey: "key1", + supportedKeys: []string{"ed25519"}, req: &goasigner.PresentationProofRequest{ Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key123", Type: "ed25519", }, nil }, - WithKeyStub: func(key string) signer.Signer { - return &signerfakes.FakeSigner{ + WithKeyStub: func(key string) signer.Vault { + return &signerfakes.FakeVault{ SignStub: func(data []byte) ([]byte, error) { return []byte("test signature"), nil }, @@ -395,26 +401,26 @@ func TestService_PresentationProof(t *testing.T) { contexts: []string{"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"}, types: []string{verifiable.VPType}, proofPurpose: "assertionMethod", - proofType: "Ed25519Signature2018", - proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), - proofVerificationMethod: "key123", + proofType: "JsonWebSignature2020", + proofVerificationMethod: "issuer#key123", }, { - name: "valid presentation and signer key type ecdsa-p256", - defaultKey: "key1", + name: "valid presentation and signer key type ecdsa-p256", + defaultKey: "key1", + supportedKeys: []string{"ed25519", "ecdsa-p256"}, req: &goasigner.PresentationProofRequest{ Key: ptr.String("key2"), Presentation: []byte(validPresentation), }, - signer: &signerfakes.FakeSigner{ - KeyStub: func(ctx context.Context, key string) (*signer.SignKey, error) { - return &signer.SignKey{ + signer: &signerfakes.FakeVault{ + KeyStub: func(ctx context.Context, key string) (*signer.VaultKey, error) { + return &signer.VaultKey{ Name: "key123", Type: "ecdsa-p256", }, nil }, - WithKeyStub: func(key string) signer.Signer { - return &signerfakes.FakeSigner{ + WithKeyStub: func(key string) signer.Vault { + return &signerfakes.FakeVault{ SignStub: func(data []byte) ([]byte, error) { return []byte("test signature"), nil }, @@ -426,19 +432,18 @@ func TestService_PresentationProof(t *testing.T) { contexts: []string{"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/examples/v1"}, types: []string{verifiable.VPType}, proofPurpose: "assertionMethod", - proofType: "EcdsaSecp256k1Signature2019", - proofValue: base64.RawURLEncoding.EncodeToString([]byte("test signature")), - proofVerificationMethod: "key123", + proofType: "JsonWebSignature2020", + proofVerificationMethod: "issuer#key123", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - svc := signer.New(test.signer, test.defaultKey, http.DefaultClient, zap.NewNop()) + svc := signer.New(test.signer, "issuer", test.defaultKey, test.supportedKeys, http.DefaultClient, zap.NewNop()) res, err := svc.PresentationProof(context.Background(), test.req) if err != nil { assert.Nil(t, res) - assert.NotEmpty(t, test.errtext) + assert.NotEmpty(t, test.errtext, err.Error()) if e, ok := err.(*errors.Error); ok { assert.Equal(t, test.errkind, e.Kind) assert.Contains(t, e.Message, test.errtext) @@ -456,8 +461,8 @@ func TestService_PresentationProof(t *testing.T) { assert.Equal(t, test.types, vp.Type) assert.Equal(t, test.proofPurpose, vp.Proofs[0]["proofPurpose"]) assert.Equal(t, test.proofType, vp.Proofs[0]["type"]) - assert.Equal(t, test.proofValue, vp.Proofs[0]["proofValue"]) assert.Equal(t, test.proofVerificationMethod, vp.Proofs[0]["verificationMethod"]) + assert.NotEmpty(t, vp.Proofs[0]["jws"]) } }) } diff --git a/internal/service/signer/signerfakes/fake_signer.go b/internal/service/signer/signerfakes/fake_vault.go similarity index 74% rename from internal/service/signer/signerfakes/fake_signer.go rename to internal/service/signer/signerfakes/fake_vault.go index 9cd9bfbec59386f657a0a197d127c26462dca3b4..320c5560c3f38fc57a6bee825c11f55b5583af9d 100644 --- a/internal/service/signer/signerfakes/fake_signer.go +++ b/internal/service/signer/signerfakes/fake_vault.go @@ -8,19 +8,19 @@ import ( "code.vereign.com/gaiax/tsa/signer/internal/service/signer" ) -type FakeSigner struct { - KeyStub func(context.Context, string) (*signer.SignKey, error) +type FakeVault struct { + KeyStub func(context.Context, string) (*signer.VaultKey, error) keyMutex sync.RWMutex keyArgsForCall []struct { arg1 context.Context arg2 string } keyReturns struct { - result1 *signer.SignKey + result1 *signer.VaultKey result2 error } keyReturnsOnCall map[int]struct { - result1 *signer.SignKey + result1 *signer.VaultKey result2 error } SignStub func([]byte) ([]byte, error) @@ -36,22 +36,22 @@ type FakeSigner struct { result1 []byte result2 error } - WithKeyStub func(string) signer.Signer + WithKeyStub func(string) signer.Vault withKeyMutex sync.RWMutex withKeyArgsForCall []struct { arg1 string } withKeyReturns struct { - result1 signer.Signer + result1 signer.Vault } withKeyReturnsOnCall map[int]struct { - result1 signer.Signer + result1 signer.Vault } invocations map[string][][]interface{} invocationsMutex sync.RWMutex } -func (fake *FakeSigner) Key(arg1 context.Context, arg2 string) (*signer.SignKey, error) { +func (fake *FakeVault) Key(arg1 context.Context, arg2 string) (*signer.VaultKey, error) { fake.keyMutex.Lock() ret, specificReturn := fake.keyReturnsOnCall[len(fake.keyArgsForCall)] fake.keyArgsForCall = append(fake.keyArgsForCall, struct { @@ -71,52 +71,52 @@ func (fake *FakeSigner) Key(arg1 context.Context, arg2 string) (*signer.SignKey, return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeSigner) KeyCallCount() int { +func (fake *FakeVault) KeyCallCount() int { fake.keyMutex.RLock() defer fake.keyMutex.RUnlock() return len(fake.keyArgsForCall) } -func (fake *FakeSigner) KeyCalls(stub func(context.Context, string) (*signer.SignKey, error)) { +func (fake *FakeVault) KeyCalls(stub func(context.Context, string) (*signer.VaultKey, error)) { fake.keyMutex.Lock() defer fake.keyMutex.Unlock() fake.KeyStub = stub } -func (fake *FakeSigner) KeyArgsForCall(i int) (context.Context, string) { +func (fake *FakeVault) KeyArgsForCall(i int) (context.Context, string) { fake.keyMutex.RLock() defer fake.keyMutex.RUnlock() argsForCall := fake.keyArgsForCall[i] return argsForCall.arg1, argsForCall.arg2 } -func (fake *FakeSigner) KeyReturns(result1 *signer.SignKey, result2 error) { +func (fake *FakeVault) KeyReturns(result1 *signer.VaultKey, result2 error) { fake.keyMutex.Lock() defer fake.keyMutex.Unlock() fake.KeyStub = nil fake.keyReturns = struct { - result1 *signer.SignKey + result1 *signer.VaultKey result2 error }{result1, result2} } -func (fake *FakeSigner) KeyReturnsOnCall(i int, result1 *signer.SignKey, result2 error) { +func (fake *FakeVault) KeyReturnsOnCall(i int, result1 *signer.VaultKey, result2 error) { fake.keyMutex.Lock() defer fake.keyMutex.Unlock() fake.KeyStub = nil if fake.keyReturnsOnCall == nil { fake.keyReturnsOnCall = make(map[int]struct { - result1 *signer.SignKey + result1 *signer.VaultKey result2 error }) } fake.keyReturnsOnCall[i] = struct { - result1 *signer.SignKey + result1 *signer.VaultKey result2 error }{result1, result2} } -func (fake *FakeSigner) Sign(arg1 []byte) ([]byte, error) { +func (fake *FakeVault) Sign(arg1 []byte) ([]byte, error) { var arg1Copy []byte if arg1 != nil { arg1Copy = make([]byte, len(arg1)) @@ -140,26 +140,26 @@ func (fake *FakeSigner) Sign(arg1 []byte) ([]byte, error) { return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeSigner) SignCallCount() int { +func (fake *FakeVault) SignCallCount() int { fake.signMutex.RLock() defer fake.signMutex.RUnlock() return len(fake.signArgsForCall) } -func (fake *FakeSigner) SignCalls(stub func([]byte) ([]byte, error)) { +func (fake *FakeVault) SignCalls(stub func([]byte) ([]byte, error)) { fake.signMutex.Lock() defer fake.signMutex.Unlock() fake.SignStub = stub } -func (fake *FakeSigner) SignArgsForCall(i int) []byte { +func (fake *FakeVault) SignArgsForCall(i int) []byte { fake.signMutex.RLock() defer fake.signMutex.RUnlock() argsForCall := fake.signArgsForCall[i] return argsForCall.arg1 } -func (fake *FakeSigner) SignReturns(result1 []byte, result2 error) { +func (fake *FakeVault) SignReturns(result1 []byte, result2 error) { fake.signMutex.Lock() defer fake.signMutex.Unlock() fake.SignStub = nil @@ -169,7 +169,7 @@ func (fake *FakeSigner) SignReturns(result1 []byte, result2 error) { }{result1, result2} } -func (fake *FakeSigner) SignReturnsOnCall(i int, result1 []byte, result2 error) { +func (fake *FakeVault) SignReturnsOnCall(i int, result1 []byte, result2 error) { fake.signMutex.Lock() defer fake.signMutex.Unlock() fake.SignStub = nil @@ -185,7 +185,7 @@ func (fake *FakeSigner) SignReturnsOnCall(i int, result1 []byte, result2 error) }{result1, result2} } -func (fake *FakeSigner) WithKey(arg1 string) signer.Signer { +func (fake *FakeVault) WithKey(arg1 string) signer.Vault { fake.withKeyMutex.Lock() ret, specificReturn := fake.withKeyReturnsOnCall[len(fake.withKeyArgsForCall)] fake.withKeyArgsForCall = append(fake.withKeyArgsForCall, struct { @@ -204,49 +204,49 @@ func (fake *FakeSigner) WithKey(arg1 string) signer.Signer { return fakeReturns.result1 } -func (fake *FakeSigner) WithKeyCallCount() int { +func (fake *FakeVault) WithKeyCallCount() int { fake.withKeyMutex.RLock() defer fake.withKeyMutex.RUnlock() return len(fake.withKeyArgsForCall) } -func (fake *FakeSigner) WithKeyCalls(stub func(string) signer.Signer) { +func (fake *FakeVault) WithKeyCalls(stub func(string) signer.Vault) { fake.withKeyMutex.Lock() defer fake.withKeyMutex.Unlock() fake.WithKeyStub = stub } -func (fake *FakeSigner) WithKeyArgsForCall(i int) string { +func (fake *FakeVault) WithKeyArgsForCall(i int) string { fake.withKeyMutex.RLock() defer fake.withKeyMutex.RUnlock() argsForCall := fake.withKeyArgsForCall[i] return argsForCall.arg1 } -func (fake *FakeSigner) WithKeyReturns(result1 signer.Signer) { +func (fake *FakeVault) WithKeyReturns(result1 signer.Vault) { fake.withKeyMutex.Lock() defer fake.withKeyMutex.Unlock() fake.WithKeyStub = nil fake.withKeyReturns = struct { - result1 signer.Signer + result1 signer.Vault }{result1} } -func (fake *FakeSigner) WithKeyReturnsOnCall(i int, result1 signer.Signer) { +func (fake *FakeVault) WithKeyReturnsOnCall(i int, result1 signer.Vault) { fake.withKeyMutex.Lock() defer fake.withKeyMutex.Unlock() fake.WithKeyStub = nil if fake.withKeyReturnsOnCall == nil { fake.withKeyReturnsOnCall = make(map[int]struct { - result1 signer.Signer + result1 signer.Vault }) } fake.withKeyReturnsOnCall[i] = struct { - result1 signer.Signer + result1 signer.Vault }{result1} } -func (fake *FakeSigner) Invocations() map[string][][]interface{} { +func (fake *FakeVault) Invocations() map[string][][]interface{} { fake.invocationsMutex.RLock() defer fake.invocationsMutex.RUnlock() fake.keyMutex.RLock() @@ -262,7 +262,7 @@ func (fake *FakeSigner) Invocations() map[string][][]interface{} { return copiedInvocations } -func (fake *FakeSigner) recordInvocation(key string, args []interface{}) { +func (fake *FakeVault) recordInvocation(key string, args []interface{}) { fake.invocationsMutex.Lock() defer fake.invocationsMutex.Unlock() if fake.invocations == nil { @@ -274,4 +274,4 @@ func (fake *FakeSigner) recordInvocation(key string, args []interface{}) { fake.invocations[key] = append(fake.invocations[key], args) } -var _ signer.Signer = new(FakeSigner) +var _ signer.Vault = new(FakeVault)