diff --git a/auth/services/notary/notary.go b/auth/services/notary/notary.go index f24d20abd3..739b485548 100644 --- a/auth/services/notary/notary.go +++ b/auth/services/notary/notary.go @@ -107,14 +107,14 @@ func NewNotary(config Config, vcr vcr.VCR, keyResolver types.KeyResolver, keySto // If the duration is 0 than the default duration is used. func (n *notary) DrawUpContract(ctx context.Context, template contract.Template, orgID did.DID, validFrom time.Time, validDuration time.Duration, organizationCredential *vc.VerifiableCredential) (*contract.Contract, error) { // Test if the org in managed by this node: - signingKeyID, err := n.keyResolver.ResolveSigningKeyID(orgID, &validFrom) + signingKeyID, _, err := n.keyResolver.ResolveKey(orgID, &validFrom, types.NutsSigningKeyType) if errors.Is(err, types.ErrNotFound) { return nil, services.InvalidContractRequestError{Message: "no valid organization credential at provided validFrom date"} } else if err != nil { return nil, fmt.Errorf("could not draw up contract: %w", err) } - if !n.privateKeyStore.Exists(ctx, signingKeyID) { + if !n.privateKeyStore.Exists(ctx, signingKeyID.String()) { return nil, services.InvalidContractRequestError{Message: fmt.Errorf("organization is not managed by this node: %w", ErrMissingOrganizationKey)} } diff --git a/auth/services/notary/notary_test.go b/auth/services/notary/notary_test.go index 350cc1dc40..84eb416d24 100644 --- a/auth/services/notary/notary_test.go +++ b/auth/services/notary/notary_test.go @@ -54,7 +54,7 @@ func TestContract_DrawUpContract(t *testing.T) { duration := 10 * time.Minute // Create DID document for org - keyID := orgID + keyID := orgID.URI() keyID.Fragment = "key-1" searchTerms := []vcr.SearchTerm{ @@ -69,7 +69,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("draw up valid contract", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, types.NutsSigningKeyType).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential}, nil) @@ -84,7 +84,7 @@ func TestContract_DrawUpContract(t *testing.T) { test := buildContext(t) defer test.ctrl.Finish() - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, gomock.Any(), types.NutsSigningKeyType).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) drawnUpContract, err := test.notary.DrawUpContract(ctx, template, orgID, validFrom, duration, &testCredential) @@ -97,7 +97,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("no given duration uses default", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential}, nil) @@ -111,7 +111,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("no given time uses time.Now()", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &time.Time{}, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential}, nil) @@ -129,7 +129,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - unknown organization", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return("", types.ErrNotFound) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(ssi.URI{}, nil, types.ErrNotFound) drawnUpContract, err := test.notary.DrawUpContract(ctx, template, orgID, validFrom, duration, nil) @@ -140,7 +140,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - unknown private key", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(false) drawnUpContract, err := test.notary.DrawUpContract(ctx, template, orgID, validFrom, duration, nil) @@ -152,7 +152,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - other DID resolver error", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return("", errors.New("error occurred")) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(ssi.URI{}, nil, errors.New("error occurred")) drawnUpContract, err := test.notary.DrawUpContract(ctx, template, orgID, validFrom, duration, nil) @@ -163,7 +163,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - could not find credential", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return(nil, errors.New("error occurred")) @@ -176,7 +176,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - render error", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential}, nil) @@ -193,7 +193,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("ok - multiple (matching) VCs", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential, testCredential}, nil) @@ -210,7 +210,7 @@ func TestContract_DrawUpContract(t *testing.T) { testCredential2 := vc.VerifiableCredential{} _ = json.Unmarshal([]byte(jsonld.TestCredential), &testCredential2) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) test.vcr.EXPECT().Search(context.Background(), searchTerms, false, nil).Return([]vc.VerifiableCredential{testCredential, testCredential2}, nil) @@ -223,7 +223,7 @@ func TestContract_DrawUpContract(t *testing.T) { t.Run("nok - given VC does not contain organization name", func(t *testing.T) { test := buildContext(t) - test.keyResolver.EXPECT().ResolveSigningKeyID(orgID, gomock.Any()).Return(keyID.String(), nil) + test.keyResolver.EXPECT().ResolveKey(orgID, &validFrom, gomock.Any()).Return(keyID, nil, nil) test.keyStore.EXPECT().Exists(ctx, keyID.String()).Return(true) drawnUpContract, err := test.notary.DrawUpContract(ctx, template, orgID, validFrom, duration, &vc.VerifiableCredential{}) diff --git a/auth/services/oauth/authz_server.go b/auth/services/oauth/authz_server.go index f07c5ae439..8ffb1aae14 100644 --- a/auth/services/oauth/authz_server.go +++ b/auth/services/oauth/authz_server.go @@ -370,7 +370,7 @@ func (s *authzServer) validateIssuer(vContext *validationContext) error { } validationTime := vContext.jwtBearerToken.IssuedAt() - if _, err := s.keyResolver.ResolveSigningKey(vContext.kid, &validationTime); err != nil { + if _, err := s.keyResolver.ResolveKeyByID(vContext.kid, &validationTime, types.NutsSigningKeyType); err != nil { return fmt.Errorf(errInvalidIssuerKeyFmt, err) } @@ -422,11 +422,11 @@ func (s *authzServer) validateSubject(ctx context.Context, validationCtx *valida validationCtx.authorizer = subject iat := validationCtx.jwtBearerToken.IssuedAt() - signingKeyID, err := s.keyResolver.ResolveSigningKeyID(*subject, &iat) + signingKeyID, _, err := s.keyResolver.ResolveKey(*subject, &iat, types.NutsSigningKeyType) if err != nil { return err } - if !s.privateKeyStore.Exists(ctx, signingKeyID) { + if !s.privateKeyStore.Exists(ctx, signingKeyID.String()) { return fmt.Errorf("subject.vendor: %s is not managed by this node", subject) } @@ -494,7 +494,7 @@ func (s *authzServer) parseAndValidateJwtBearerToken(context *validationContext) var kidHdr string token, err := nutsCrypto.ParseJWT(context.rawJwtBearerToken, func(kid string) (crypto.PublicKey, error) { kidHdr = kid - return s.keyResolver.ResolveSigningKey(kid, nil) + return s.keyResolver.ResolveKeyByID(kid, nil, types.NutsSigningKeyType) }, jwt.WithAcceptableSkew(s.clockSkew)) if err != nil { return err @@ -512,7 +512,7 @@ func (s *authzServer) IntrospectAccessToken(ctx context.Context, accessToken str if !s.privateKeyStore.Exists(ctx, kid) { return nil, fmt.Errorf("JWT signing key not present on this node (kid=%s)", kid) } - return s.keyResolver.ResolveSigningKey(kid, nil) + return s.keyResolver.ResolveKeyByID(kid, nil, types.NutsSigningKeyType) }, jwt.WithAcceptableSkew(s.clockSkew)) if err != nil { return nil, err @@ -573,11 +573,11 @@ func (s *authzServer) buildAccessToken(ctx context.Context, requester did.DID, a } // Sign with the private key of the issuer - signingKeyID, err := s.keyResolver.ResolveSigningKeyID(authorizer, &issueTime) + signingKeyID, _, err := s.keyResolver.ResolveKey(authorizer, &issueTime, types.NutsSigningKeyType) if err != nil { return "", accessToken, err } - token, err := s.privateKeyStore.SignJWT(ctx, keyVals, nil, signingKeyID) + token, err := s.privateKeyStore.SignJWT(ctx, keyVals, nil, signingKeyID.String()) if err != nil { return token, accessToken, fmt.Errorf("could not build accessToken: %w", err) } diff --git a/auth/services/oauth/authz_server_test.go b/auth/services/oauth/authz_server_test.go index c19cae1449..b4f926243a 100644 --- a/auth/services/oauth/authz_server_test.go +++ b/auth/services/oauth/authz_server_test.go @@ -125,8 +125,8 @@ func TestAuth_CreateAccessToken(t *testing.T) { ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil) ctx.contractNotary.EXPECT().VerifyVP(gomock.Any(), nil).Return(nil, errors.New("identity validation failed")) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) ctx.keyStore.EXPECT().Exists(ctx.audit, authorizerSigningKeyID.String()).Return(true) tokenCtx := validContext() signToken(tokenCtx) @@ -140,7 +140,7 @@ func TestAuth_CreateAccessToken(t *testing.T) { t.Run("JWT validity too long", func(t *testing.T) { ctx := createContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) tokenCtx := validContext() tokenCtx.jwtBearerToken.Set(jwt.ExpirationKey, time.Now().Add(10*time.Second)) @@ -157,8 +157,8 @@ func TestAuth_CreateAccessToken(t *testing.T) { ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil) ctx.keyStore.EXPECT().Exists(ctx.audit, authorizerSigningKeyID.String()).Return(true) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) ctx.contractNotary.EXPECT().VerifyVP(gomock.Any(), nil).Return(services.TestVPVerificationResult{Val: contract.Invalid, FailureReason: "because of reasons"}, nil) tokenCtx := validContext() @@ -172,8 +172,8 @@ func TestAuth_CreateAccessToken(t *testing.T) { t.Run("error detail masking", func(t *testing.T) { setup := func(ctx *testContext) *testContext { - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil).AnyTimes() - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil).AnyTimes() + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil).AnyTimes() + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil).AnyTimes() ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil).AnyTimes() ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(getAuthorizerDIDDocument(), nil, nil).AnyTimes() ctx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil).AnyTimes() @@ -218,8 +218,8 @@ func TestAuth_CreateAccessToken(t *testing.T) { t.Run("valid - without user identity", func(t *testing.T) { testCtx := createContext(t) - testCtx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) - testCtx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + testCtx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) + testCtx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) testCtx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil) testCtx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(getAuthorizerDIDDocument(), nil, nil).AnyTimes() testCtx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil) @@ -240,8 +240,8 @@ func TestAuth_CreateAccessToken(t *testing.T) { t.Run("valid - all fields", func(t *testing.T) { ctx := createContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil) ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(getAuthorizerDIDDocument(), nil, nil).AnyTimes() ctx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil) @@ -265,7 +265,7 @@ func TestAuth_CreateAccessToken(t *testing.T) { t.Run("missing organization credential", func(t *testing.T) { ctx := createContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{}, nil) ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(getAuthorizerDIDDocument(), nil, nil).AnyTimes() @@ -290,7 +290,7 @@ func TestService_validateIssuer(t *testing.T) { ctx := createContext(t) tokenCtx := validContext() - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential}, nil) err := ctx.oauthService.validateIssuer(tokenCtx) @@ -302,7 +302,7 @@ func TestService_validateIssuer(t *testing.T) { ctx := createContext(t) tokenCtx := validContext() - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{testCredential, testCredential}, nil) err := ctx.oauthService.validateIssuer(tokenCtx) @@ -322,7 +322,7 @@ func TestService_validateIssuer(t *testing.T) { ctx := createContext(t) tokenCtx := validContext() - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).Return(requesterSigningKey.Public(), nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return(nil, errors.New("error occurred")) err := ctx.oauthService.validateIssuer(tokenCtx) @@ -332,7 +332,7 @@ func TestService_validateIssuer(t *testing.T) { ctx := createContext(t) tokenCtx := validContext() - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).Return(requesterSigningKey.Public(), nil) ctx.nameResolver.EXPECT().Search(context.Background(), searchTerms, false, gomock.Any()).Return([]vc.VerifiableCredential{}, nil) err := ctx.oauthService.validateIssuer(tokenCtx) @@ -343,7 +343,7 @@ func TestService_validateIssuer(t *testing.T) { tokenCtx := validContext() - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(nil, fmt.Errorf("not found")) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(nil, fmt.Errorf("not found")) err := ctx.oauthService.validateIssuer(tokenCtx) assert.EqualError(t, err, "invalid jwt.issuer key ID: not found") @@ -357,7 +357,7 @@ func TestService_validateSubject(t *testing.T) { tokenCtx := validContext() tokenCtx.jwtBearerToken.Set(jwt.SubjectKey, authorizerDID.String()) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) ctx.keyStore.EXPECT().Exists(ctx.audit, authorizerSigningKeyID.String()).Return(true) err := ctx.oauthService.validateSubject(ctx.audit, tokenCtx) @@ -387,7 +387,7 @@ func TestService_validateSubject(t *testing.T) { tokenCtx := validContext() tokenCtx.jwtBearerToken.Set(jwt.SubjectKey, authorizerDID.String()) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) ctx.keyStore.EXPECT().Exists(ctx.audit, authorizerSigningKeyID.String()).Return(false) err := ctx.oauthService.validateSubject(ctx.audit, tokenCtx) @@ -587,7 +587,7 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { keyID := "did:nuts:somedid#key-id" - ctx.keyResolver.EXPECT().ResolveSigningKey(keyID, gomock.Any()).Return(privateKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(keyID, nil, types.NutsSigningKeyType).Return(privateKey.Public(), nil) // alg: RS256 token := jwt.New() @@ -608,7 +608,7 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { tokenCtx := validContext() signToken(tokenCtx) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).Return(requesterSigningKey.PublicKey, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).Return(requesterSigningKey.PublicKey, nil) err := ctx.oauthService.parseAndValidateJwtBearerToken(tokenCtx) assert.NoError(t, err) @@ -625,7 +625,7 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { tokenCtx.jwtBearerToken.Set(jwt.ExpirationKey, time.Now().Add(-4*time.Minute)) signToken(tokenCtx) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).Return(requesterSigningKey.PublicKey, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).Return(requesterSigningKey.PublicKey, nil) err := ctx.oauthService.parseAndValidateJwtBearerToken(tokenCtx) assert.NoError(t, err) @@ -640,7 +640,7 @@ func TestService_parseAndValidateJwtBearerToken(t *testing.T) { tokenCtx.jwtBearerToken.Set(jwt.ExpirationKey, time.Now().Add(-4*time.Minute)) signToken(tokenCtx) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).Return(requesterSigningKey.PublicKey, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).Return(requesterSigningKey.PublicKey, nil) err := ctx.oauthService.parseAndValidateJwtBearerToken(tokenCtx) assert.EqualError(t, err, "exp not satisfied") @@ -653,7 +653,7 @@ func TestService_buildAccessToken(t *testing.T) { ctx.oauthService.accessTokenLifeSpan = secureAccessTokenLifeSpan * 10 // ignored by secureMode == true ctx.oauthService.Configure(5000, true) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(authorizerDID, gomock.Any()).MinTimes(1).Return(authorizerSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(authorizerDID, gomock.Any(), types.NutsSigningKeyType).MinTimes(1).Return(authorizerSigningKeyID, authorizerSigningKey, nil) var actualClaims map[string]interface{} ctx.keyStore.EXPECT().SignJWT(gomock.Any(), gomock.Any(), nil, gomock.Any()). @@ -693,7 +693,7 @@ func TestService_IntrospectAccessToken(t *testing.T) { t.Run("validate access token", func(t *testing.T) { ctx := createContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) ctx.keyStore.EXPECT().Exists(ctx.audit, requesterSigningKeyID.String()).Return(true) // First build an access token @@ -714,7 +714,7 @@ func TestService_IntrospectAccessToken(t *testing.T) { t.Run("invalid signature", func(t *testing.T) { ctx := createContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(requesterSigningKey.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKey.Public(), nil) ctx.keyStore.EXPECT().Exists(ctx.audit, requesterSigningKeyID.String()).Return(true) // First build an access token @@ -747,7 +747,7 @@ func TestService_IntrospectAccessToken(t *testing.T) { ctx := createContext(t) ctx.keyStore.EXPECT().Exists(ctx.audit, requesterSigningKeyID.String()).Return(true) - ctx.keyResolver.EXPECT().ResolveSigningKey(requesterSigningKeyID.String(), gomock.Any()).MinTimes(1).Return(nil, types.ErrNotFound) + ctx.keyResolver.EXPECT().ResolveKeyByID(requesterSigningKeyID.String(), nil, types.NutsSigningKeyType).MinTimes(1).Return(nil, types.ErrNotFound) // First build an access token tokenCtx := validContext() diff --git a/auth/services/oauth/relying_party.go b/auth/services/oauth/relying_party.go index 4a6e8e5570..e521fc440f 100644 --- a/auth/services/oauth/relying_party.go +++ b/auth/services/oauth/relying_party.go @@ -118,12 +118,11 @@ func (s *relyingParty) CreateJwtGrant(ctx context.Context, request services.Crea keyVals := claimsFromRequest(request, endpointURL) - now := time.Now() - signingKeyID, err := s.keyResolver.ResolveSigningKeyID(*requester, &now) + signingKeyID, _, err := s.keyResolver.ResolveKey(*requester, nil, types.NutsSigningKeyType) if err != nil { return nil, err } - signingString, err := s.privateKeyStore.SignJWT(ctx, keyVals, nil, signingKeyID) + signingString, err := s.privateKeyStore.SignJWT(ctx, keyVals, nil, signingKeyID.String()) if err != nil { return nil, err } diff --git a/auth/services/oauth/relying_party_test.go b/auth/services/oauth/relying_party_test.go index 84c83cbfe0..c6bc3a7743 100644 --- a/auth/services/oauth/relying_party_test.go +++ b/auth/services/oauth/relying_party_test.go @@ -151,7 +151,7 @@ func TestService_CreateJwtBearerToken(t *testing.T) { ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(authorizerDIDDocument, nil, nil).AnyTimes() ctx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(requesterDID, gomock.Any()).MinTimes(1).Return(requesterSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(requesterDID, nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKeyID, requesterSigningKey, nil) ctx.keyStore.EXPECT().SignJWT(gomock.Any(), gomock.Any(), nil, requesterSigningKeyID.String()).Return("token", nil) token, err := ctx.relyingParty.CreateJwtGrant(ctx.audit, request) @@ -168,7 +168,7 @@ func TestService_CreateJwtBearerToken(t *testing.T) { ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(authorizerDIDDocument, nil, nil).AnyTimes() ctx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(requesterDID, gomock.Any()).MinTimes(1).Return(requesterSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(requesterDID, nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKeyID, requesterSigningKey, nil) ctx.keyStore.EXPECT().SignJWT(gomock.Any(), gomock.Any(), nil, requesterSigningKeyID.String()).Return("token", nil) validRequest := request @@ -229,7 +229,7 @@ func TestService_CreateJwtBearerToken(t *testing.T) { ctx.didResolver.EXPECT().Resolve(authorizerDID, gomock.Any()).Return(authorizerDIDDocument, nil, nil).AnyTimes() ctx.serviceResolver.EXPECT().GetCompoundServiceEndpoint(authorizerDID, expectedService, services.OAuthEndpointType, true).Return(expectedAudience, nil) - ctx.keyResolver.EXPECT().ResolveSigningKeyID(requesterDID, gomock.Any()).MinTimes(1).Return(requesterSigningKeyID.String(), nil) + ctx.keyResolver.EXPECT().ResolveKey(requesterDID, nil, types.NutsSigningKeyType).MinTimes(1).Return(requesterSigningKeyID, requesterSigningKey, nil) ctx.keyStore.EXPECT().SignJWT(gomock.Any(), gomock.Any(), nil, requesterSigningKeyID.String()).Return("", errors.New("boom!")) token, err := ctx.relyingParty.CreateJwtGrant(ctx.audit, request) diff --git a/crypto/api/v1/api.go b/crypto/api/v1/api.go index 0b8cdaf635..e01a5ab97a 100644 --- a/crypto/api/v1/api.go +++ b/crypto/api/v1/api.go @@ -195,18 +195,14 @@ func (w *Wrapper) resolvePublicKey(id *did.DID) (key crypt.PublicKey, keyID ssi. if id.IsURL() { // Assume it is a keyId now := time.Now() - key, err = w.K.ResolveRelationKey(id.String(), &now, types.KeyAgreement) + key, err = w.K.ResolveKeyByID(id.String(), &now, types.KeyAgreement) if err != nil { return nil, ssi.URI{}, err } keyID = id.URI() } else { // Assume it is a DID - key, err = w.K.ResolveKeyAgreementKey(*id) - if err != nil { - return nil, ssi.URI{}, err - } - keyID, err = w.K.ResolveRelationKeyID(*id, types.KeyAgreement) + keyID, key, err = w.K.ResolveKey(*id, nil, types.KeyAgreement) if err != nil { return nil, ssi.URI{}, err } diff --git a/crypto/api/v1/api_test.go b/crypto/api/v1/api_test.go index 7af59456b2..82ddd24462 100644 --- a/crypto/api/v1/api_test.go +++ b/crypto/api/v1/api_test.go @@ -244,7 +244,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveKeyAgreementKey fails, returns 400", func(t *testing.T) { + t.Run("ResolveKey fails, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -252,14 +252,14 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()).Return(nil, errors.New("FAIL")) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL")) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "invalid receiver: FAIL") assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveRelationKeyID fails, returns 400", func(t *testing.T) { + t.Run("ResolveKey fails, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -267,15 +267,14 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, errors.New("FAIL")) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL")) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "invalid receiver: FAIL") assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveRelationKey fails, returns 400", func(t *testing.T) { + t.Run("ResolveKeyByID fails, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -283,14 +282,14 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveRelationKey(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, errors.New("FAIL")) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, errors.New("FAIL")) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "invalid receiver: FAIL") assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveKeyAgreementKey not found, returns 400", func(t *testing.T) { + t.Run("KeyAgreement key not found, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -298,14 +297,14 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()).Return(nil, types.ErrNotFound) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, types.ErrNotFound) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "unable to locate receiver did:nuts:12345: unable to find the DID document") assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveRelationKeyID not found, returns 400", func(t *testing.T) { + t.Run("Key not found, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -313,15 +312,14 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, types.ErrNotFound) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, types.ErrNotFound) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "unable to locate receiver did:nuts:12345: unable to find the DID document") assert.Equal(t, err.(core.HTTPStatusCodeError).StatusCode(), http.StatusBadRequest) assert.Empty(t, jwe) }) - t.Run("ResolveRelationKey not found, returns 400", func(t *testing.T) { + t.Run("KeyAgreement key not found, returns 400", func(t *testing.T) { ctx := newMockContext(t) headers := map[string]interface{}{"typ": "JWE"} request := EncryptJweRequest{ @@ -329,7 +327,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, Headers: headers, } - ctx.keyResolver.EXPECT().ResolveRelationKey(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, types.ErrNotFound) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, types.ErrNotFound) jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) assert.EqualError(t, err, "unable to locate receiver did:nuts:12345#key-1: unable to find the DID document") @@ -360,9 +358,8 @@ func TestWrapper_EncryptJwe(t *testing.T) { } did, _ := ssi.ParseURI("did:nuts:12345") ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("", errors.New("b00m!")) - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(*did, nil) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil) jwe, err := ctx.client.EncryptJwe(audit.TestContext(), EncryptJweRequestObject{Body: &request}) @@ -380,8 +377,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, } ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil) - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(*did, nil) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil) resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) @@ -399,7 +395,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { Payload: payload, } ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil) - ctx.keyResolver.EXPECT().ResolveRelationKey(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(*did, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(*did, nil) resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) @@ -417,8 +413,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { } did, _ := ssi.ParseURI(kid) ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil) - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(*did, nil) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil) resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) @@ -434,8 +429,7 @@ func TestWrapper_EncryptJwe(t *testing.T) { Receiver: did.String(), } ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil) - ctx.keyResolver.EXPECT().ResolveKeyAgreementKey(gomock.Any()) - ctx.keyResolver.EXPECT().ResolveRelationKeyID(gomock.Any(), types.KeyAgreement).Return(*did, nil) + ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil) resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request}) diff --git a/network/dag/pal.go b/network/dag/pal.go index 59d058b7a8..750d3cef6e 100644 --- a/network/dag/pal.go +++ b/network/dag/pal.go @@ -58,7 +58,7 @@ func (pal PAL) Encrypt(keyResolver types.KeyResolver) (EncryptedPAL, error) { var recipients [][]byte for _, recipient := range pal { recipients = append(recipients, []byte(recipient.String())) - rawKak, err := keyResolver.ResolveKeyAgreementKey(recipient) + _, rawKak, err := keyResolver.ResolveKey(recipient, nil, types.KeyAgreement) if err != nil { return nil, fmt.Errorf("unable to resolve keyAgreement key (recipient=%s): %w", recipient, err) } diff --git a/network/dag/pal_test.go b/network/dag/pal_test.go index b6df7d7927..c5e78c3a0c 100644 --- a/network/dag/pal_test.go +++ b/network/dag/pal_test.go @@ -24,6 +24,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + ssi "github.com/nuts-foundation/go-did" "github.com/stretchr/testify/require" "testing" @@ -46,8 +47,8 @@ func TestEncryptPal(t *testing.T) { // Encrypt ctrl := gomock.NewController(t) keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveKeyAgreementKey(*pA).Return(pkA.Public(), nil) - keyResolver.EXPECT().ResolveKeyAgreementKey(*pB).Return(pkB.Public(), nil) + keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, pkA.Public(), nil) + keyResolver.EXPECT().ResolveKey(*pB, nil, types.KeyAgreement).Return(ssi.URI{}, pkB.Public(), nil) expected := PAL{*pA, *pB} pal, err := expected.Encrypt(keyResolver) require.NoError(t, err) @@ -70,7 +71,7 @@ func TestEncryptPal(t *testing.T) { t.Run("error - keyAgreement key type is not supported", func(t *testing.T) { ctrl := gomock.NewController(t) keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveKeyAgreementKey(*pA).Return(&rsa.PublicKey{}, nil) + keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, &rsa.PublicKey{}, nil) pal, err := PAL{*pA}.Encrypt(keyResolver) assert.Nil(t, pal) assert.EqualError(t, err, "resolved keyAgreement key is not an elliptic curve key (recipient=did:nuts:A)") @@ -78,7 +79,7 @@ func TestEncryptPal(t *testing.T) { t.Run("error - no keyAgreements", func(t *testing.T) { ctrl := gomock.NewController(t) keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveKeyAgreementKey(*pA).Return(nil, types.ErrKeyNotFound) + keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, nil, types.ErrKeyNotFound) pal, err := PAL{*pA}.Encrypt(keyResolver) assert.Nil(t, pal) assert.EqualError(t, err, "unable to resolve keyAgreement key (recipient=did:nuts:A): key not found in DID document") diff --git a/network/dag/verifier_test.go b/network/dag/verifier_test.go index 2f5a786568..8b3ba0e28d 100644 --- a/network/dag/verifier_test.go +++ b/network/dag/verifier_test.go @@ -30,8 +30,6 @@ import ( "time" "github.com/lestrrat-go/jwx/jwk" - ssi "github.com/nuts-foundation/go-did" - "github.com/nuts-foundation/go-did/did" "github.com/nuts-foundation/go-stoabs" nutsCrypto "github.com/nuts-foundation/nuts-node/crypto" "github.com/nuts-foundation/nuts-node/crypto/hash" @@ -126,7 +124,7 @@ func TestTransactionSignatureVerifier(t *testing.T) { t.Run("unable to resolve key by hash", func(t *testing.T) { d := CreateSignedTestTransaction(1, time.Now(), nil, "foo/bar", false) ctrl := gomock.NewController(t) - keyResolver := types.NewMockKeyResolver(ctrl) + keyResolver := types.NewMockNutsKeyResolver(ctrl) keyResolver.EXPECT().ResolvePublicKey(gomock.Any(), gomock.Any()).Return(nil, errors.New("failed")) err := NewTransactionSignatureVerifier(keyResolver)(nil, d) @@ -135,35 +133,12 @@ func TestTransactionSignatureVerifier(t *testing.T) { }) } -var _ types.KeyResolver = &staticKeyResolver{} var _ types.NutsKeyResolver = &staticKeyResolver{} type staticKeyResolver struct { Key crypto.PublicKey } -func (s staticKeyResolver) ResolveKeyAgreementKey(_ did.DID) (crypto.PublicKey, error) { - return s.Key, nil -} - func (s staticKeyResolver) ResolvePublicKey(_ string, _ []hash.SHA256Hash) (crypto.PublicKey, error) { return s.Key, nil } - -func (s staticKeyResolver) ResolveSigningKeyID(_ did.DID, _ *time.Time) (string, error) { - panic("implement me") -} - -func (s staticKeyResolver) ResolveSigningKey(_ string, _ *time.Time) (crypto.PublicKey, error) { - panic("implement me") -} -func (s staticKeyResolver) ResolveRelationKey(_ string, _ *time.Time, _ types.RelationType) (crypto.PublicKey, error) { - panic("implement me") -} - -func (s staticKeyResolver) ResolveAssertionKeyID(_ did.DID) (ssi.URI, error) { - panic("implement me") -} -func (s staticKeyResolver) ResolveRelationKeyID(_ did.DID, _ types.RelationType) (ssi.URI, error) { - panic("implement me") -} diff --git a/network/network_test.go b/network/network_test.go index a7621fed95..cfa478b66c 100644 --- a/network/network_test.go +++ b/network/network_test.go @@ -27,6 +27,7 @@ import ( "crypto/x509" "errors" "fmt" + ssi "github.com/nuts-foundation/go-did" testPKI "github.com/nuts-foundation/nuts-node/test/pki" "github.com/nuts-foundation/nuts-node/vdr/didservice" "github.com/nuts-foundation/nuts-node/vdr/didstore" @@ -463,8 +464,8 @@ func TestNetwork_CreateTransaction(t *testing.T) { cxt.state.EXPECT().Head(gomock.Any()) cxt.state.EXPECT().Add(gomock.Any(), gomock.Any(), payload) - cxt.keyResolver.EXPECT().ResolveKeyAgreementKey(*sender).Return(senderKey.Public(), nil) - cxt.keyResolver.EXPECT().ResolveKeyAgreementKey(*receiver).Return(receiverKey.Public(), nil) + cxt.keyResolver.EXPECT().ResolveKey(*sender, nil, vdrTypes.KeyAgreement).Return(ssi.MustParseURI("sender"), senderKey.Public(), nil) + cxt.keyResolver.EXPECT().ResolveKey(*receiver, nil, vdrTypes.KeyAgreement).Return(ssi.MustParseURI("receiver"), receiverKey.Public(), nil) _, err = cxt.network.CreateTransaction(ctx, TransactionTemplate(payloadType, payload, key).WithPrivate([]did.DID{*sender, *receiver})) assert.NoError(t, err) diff --git a/vcr/ambassador_test.go b/vcr/ambassador_test.go index 206888a40d..31127ff96d 100644 --- a/vcr/ambassador_test.go +++ b/vcr/ambassador_test.go @@ -25,6 +25,7 @@ import ( "errors" "fmt" "github.com/nuts-foundation/nuts-node/audit" + types2 "github.com/nuts-foundation/nuts-node/vdr/types" "github.com/piprate/json-gold/ld" "github.com/stretchr/testify/require" "net/http" @@ -113,12 +114,12 @@ func TestAmbassador_handleReprocessEvent(t *testing.T) { signer, _ := util.PemToPrivateKey(pem) key := crypto.NewTestKey(fmt.Sprintf("%s#1", vc.Issuer.String())) - // trust otherwise Resolve wont work + // trust otherwise Resolve won't work ctx.vcr.Trust(vc.Type[0], vc.Issuer) ctx.vcr.Trust(vc.Type[1], vc.Issuer) // mocks - ctx.keyResolver.EXPECT().ResolveSigningKey(gomock.Any(), gomock.Any()).Return(signer.Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types2.NutsSigningKeyType).Return(signer.Public(), nil) // Publish a VC payload, _ := json.Marshal(vc) diff --git a/vcr/holder/holder.go b/vcr/holder/holder.go index 6af96e9439..c19a2690a9 100644 --- a/vcr/holder/holder.go +++ b/vcr/holder/holder.go @@ -62,7 +62,7 @@ func (h vcHolder) BuildVP(ctx context.Context, credentials []vc.VerifiableCreden } } - kid, err := h.keyResolver.ResolveAssertionKeyID(*signerDID) + kid, _, err := h.keyResolver.ResolveKey(*signerDID, nil, vdr.NutsSigningKeyType) if err != nil { return nil, fmt.Errorf("unable to resolve assertion key for signing VP (did=%s): %w", *signerDID, err) } diff --git a/vcr/holder/holder_test.go b/vcr/holder/holder_test.go index cc5b0c9dd7..68d860f9e0 100644 --- a/vcr/holder/holder_test.go +++ b/vcr/holder/holder_test.go @@ -63,7 +63,7 @@ func TestHolder_BuildVP(t *testing.T) { "proof": { "created": "2021-12-24T13:21:29.087205+01:00", "jws": "eyJhbGciOiJFUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..hPM2GLc1K9d2D8Sbve004x9SumjLqaXTjWhUhvqWRwxfRWlwfp5gHDUYuRoEjhCXfLt-_u-knChVmK980N3LBw", - "proofPurpose": "assertionMethod", + "proofPurpose": "NutsSigningKeyType", "type": "JsonWebSignature2020", "verificationMethod": "` + kid + `" }, @@ -90,7 +90,7 @@ func TestHolder_BuildVP(t *testing.T) { keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(ssi.MustParseURI(kid), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(ssi.MustParseURI(kid), key.Public(), nil) holder := New(keyResolver, keyStore, nil, jsonldManager) @@ -111,7 +111,7 @@ func TestHolder_BuildVP(t *testing.T) { } keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(ssi.MustParseURI(kid), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(ssi.MustParseURI(kid), key.Public(), nil) holder := New(keyResolver, keyStore, nil, jsonldManager) @@ -130,7 +130,7 @@ func TestHolder_BuildVP(t *testing.T) { keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(vdr.TestMethodDIDA.URI(), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(vdr.TestMethodDIDA.URI(), key.Public(), nil) holder := New(keyResolver, keyStore, nil, jsonldManager) @@ -150,7 +150,7 @@ func TestHolder_BuildVP(t *testing.T) { mockVerifier := verifier.NewMockVerifier(ctrl) mockVerifier.EXPECT().Validate(testCredential, &created) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(ssi.MustParseURI(kid), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(ssi.MustParseURI(kid), key.Public(), nil) holder := New(keyResolver, keyStore, mockVerifier, jsonldManager) @@ -166,7 +166,7 @@ func TestHolder_BuildVP(t *testing.T) { mockVerifier := verifier.NewMockVerifier(ctrl) mockVerifier.EXPECT().Validate(testCredential, &created).Return(errors.New("failed")) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(ssi.MustParseURI(kid), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(ssi.MustParseURI(kid), key.Public(), nil) holder := New(keyResolver, keyStore, mockVerifier, jsonldManager) @@ -184,7 +184,7 @@ func TestHolder_BuildVP(t *testing.T) { keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveAssertionKeyID(testDID).Return(ssi.MustParseURI(kid), nil) + keyResolver.EXPECT().ResolveKey(testDID, nil, types.NutsSigningKeyType).Return(ssi.MustParseURI(kid), key.Public(), nil) holder := New(keyResolver, keyStore, nil, jsonldManager) diff --git a/vcr/holder/openid.go b/vcr/holder/openid.go index 9d3e78ed18..c2a9b53db5 100644 --- a/vcr/holder/openid.go +++ b/vcr/holder/openid.go @@ -193,10 +193,10 @@ func getPreAuthorizedCodeFromOffer(offer openid4vci.CredentialOffer) string { } func (h *openidHandler) retrieveCredential(ctx context.Context, issuerClient openid4vci.IssuerAPIClient, offer *openid4vci.CredentialDefinition, tokenResponse *openid4vci.TokenResponse) (*vc.VerifiableCredential, error) { - keyID, err := h.resolver.ResolveSigningKeyID(h.did, nil) + keyID, _, err := h.resolver.ResolveKey(h.did, nil, vdr.NutsSigningKeyType) headers := map[string]interface{}{ "typ": openid4vci.JWTTypeOpenID4VCIProof, // MUST be openid4vci-proof+jwt, which explicitly types the proof JWT as recommended in Section 3.11 of [RFC8725]. - "kid": keyID, // JOSE Header containing the key ID. If the Credential shall be bound to a DID, the kid refers to a DID URL which identifies a particular key in the DID Document that the Credential shall be bound to. + "kid": keyID.String(), // JOSE Header containing the key ID. If the Credential shall be bound to a DID, the kid refers to a DID URL which identifies a particular key in the DID Document that the Credential shall be bound to. } claims := map[string]interface{}{ "aud": issuerClient.Metadata().CredentialIssuer, @@ -204,7 +204,7 @@ func (h *openidHandler) retrieveCredential(ctx context.Context, issuerClient ope "nonce": tokenResponse.CNonce, } - proof, err := h.signer.SignJWT(ctx, claims, headers, keyID) + proof, err := h.signer.SignJWT(ctx, claims, headers, keyID.String()) if err != nil { return nil, fmt.Errorf("unable to sign request proof: %w", err) } diff --git a/vcr/holder/openid_test.go b/vcr/holder/openid_test.go index e6484aa36b..fdd4818bb4 100644 --- a/vcr/holder/openid_test.go +++ b/vcr/holder/openid_test.go @@ -98,7 +98,7 @@ func Test_wallet_HandleCredentialOffer(t *testing.T) { "nonce": nonce, }, gomock.Any(), "key-id").Return("signed-jwt", nil) keyResolver := vdrTypes.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveSigningKeyID(holderDID, nil).Return("key-id", nil) + keyResolver.EXPECT().ResolveKey(holderDID, nil, vdrTypes.NutsSigningKeyType).Return(ssi.MustParseURI("key-id"), nil, nil) nowFunc = func() time.Time { return time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC) @@ -238,7 +238,7 @@ func Test_wallet_HandleCredentialOffer(t *testing.T) { jwtSigner := crypto.NewMockJWTSigner(ctrl) jwtSigner.EXPECT().SignJWT(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()) keyResolver := vdrTypes.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveSigningKeyID(holderDID, nil) + keyResolver.EXPECT().ResolveKey(holderDID, nil, vdrTypes.NutsSigningKeyType) w := NewOpenIDHandler(holderDID, "https://holder.example.com", &http.Client{}, nil, jwtSigner, keyResolver).(*openidHandler) w.issuerClientCreator = func(_ context.Context, _ core.HTTPRequestDoer, _ string) (openid4vci.IssuerAPIClient, error) { diff --git a/vcr/issuer/issuer.go b/vcr/issuer/issuer.go index 575eb50a7a..6d1255166c 100644 --- a/vcr/issuer/issuer.go +++ b/vcr/issuer/issuer.go @@ -56,7 +56,10 @@ func NewIssuer(store Store, vcrStore types.Writer, networkPublisher Publisher, openidHandlerFn func(ctx context.Context, id did.DID) (OpenIDHandler, error), didstore didstore.Store, keyStore crypto.KeyStore, jsonldManager jsonld.JSONLD, trustConfig *trust.Config, ) Issuer { - resolver := vdrKeyResolver{didResolver: didservice.Resolver{Store: didstore}, keyResolver: keyStore} + resolver := vdrKeyResolver{ + publicKeyResolver: didservice.KeyResolver{Store: didstore}, + privateKeyResolver: keyStore, + } return &issuer{ store: store, networkPublisher: networkPublisher, diff --git a/vcr/issuer/keyresolver.go b/vcr/issuer/keyresolver.go index 367ce07617..0815519b8a 100644 --- a/vcr/issuer/keyresolver.go +++ b/vcr/issuer/keyresolver.go @@ -23,31 +23,23 @@ import ( "fmt" "github.com/nuts-foundation/go-did/did" "github.com/nuts-foundation/nuts-node/crypto" - "github.com/nuts-foundation/nuts-node/vdr/didservice" vdr "github.com/nuts-foundation/nuts-node/vdr/types" ) // vdrKeyResolver resolves private keys based upon the VDR document resolver type vdrKeyResolver struct { - didResolver vdr.DIDResolver - keyResolver crypto.KeyResolver + publicKeyResolver vdr.KeyResolver + privateKeyResolver crypto.KeyResolver } // ResolveAssertionKey is a convenience method which tries to find a assertionKey on in the VDR for a given issuerDID. func (r vdrKeyResolver) ResolveAssertionKey(ctx context.Context, issuerDID did.DID) (crypto.Key, error) { - // find did document/metadata for originating TXs - document, _, err := r.didResolver.Resolve(issuerDID, nil) - if err != nil { - return nil, err - } - - // resolve an assertionMethod key for issuer - kid, err := didservice.ExtractFirstRelationKeyIDByType(*document, vdr.AssertionMethod) + kid, _, err := r.publicKeyResolver.ResolveKey(issuerDID, nil, vdr.AssertionMethod) if err != nil { return nil, fmt.Errorf("invalid issuer: %w", err) } - key, err := r.keyResolver.Resolve(ctx, kid.String()) + key, err := r.privateKeyResolver.Resolve(ctx, kid.String()) if err != nil { return nil, fmt.Errorf("failed to resolve assertionKey: could not resolve key from keyStore: %w", err) } diff --git a/vcr/issuer/keyresolver_test.go b/vcr/issuer/keyresolver_test.go index a108344dba..8c746dc7a5 100644 --- a/vcr/issuer/keyresolver_test.go +++ b/vcr/issuer/keyresolver_test.go @@ -36,21 +36,22 @@ func Test_vdrKeyResolver_ResolveAssertionKey(t *testing.T) { issuerDID, _ := did.ParseDID("did:nuts:123") methodID := *issuerDID methodID.Fragment = "abc" - newMethod, err := did.NewVerificationMethod(methodID, ssi.JsonWebKey2020, *issuerDID, crypto.NewTestKey(issuerDID.String()+"abc").Public()) + publicKey := crypto.NewTestKey(issuerDID.String() + "abc").Public() + newMethod, err := did.NewVerificationMethod(methodID, ssi.JsonWebKey2020, *issuerDID, publicKey) require.NoError(t, err) docWithAssertionKey := &did.Document{} docWithAssertionKey.AddAssertionMethod(newMethod) t.Run("ok", func(t *testing.T) { ctrl := gomock.NewController(t) - mockDockResolver := types.NewMockDIDResolver(ctrl) - mockDockResolver.EXPECT().Resolve(*issuerDID, nil).Return(docWithAssertionKey, &types.DocumentMetadata{}, nil) - mockKeyResolver := crypto.NewMockKeyResolver(ctrl) - mockKeyResolver.EXPECT().Resolve(ctx, methodID.String()).Return(crypto.NewTestKey(methodID.String()), nil) + mockPubKeyResolver := types.NewMockKeyResolver(ctrl) + mockPubKeyResolver.EXPECT().ResolveKey(*issuerDID, nil, types.NutsSigningKeyType).Return(methodID.URI(), publicKey, nil) + mockPrivKeyResolver := crypto.NewMockKeyResolver(ctrl) + mockPrivKeyResolver.EXPECT().Resolve(ctx, methodID.String()).Return(crypto.NewTestKey(methodID.String()), nil) sut := vdrKeyResolver{ - didResolver: mockDockResolver, - keyResolver: mockKeyResolver, + publicKeyResolver: mockPubKeyResolver, + privateKeyResolver: mockPrivKeyResolver, } key, err := sut.ResolveAssertionKey(ctx, *issuerDID) @@ -62,52 +63,35 @@ func Test_vdrKeyResolver_ResolveAssertionKey(t *testing.T) { t.Run("document for issuer not found in vdr", func(t *testing.T) { ctrl := gomock.NewController(t) - mockDockResolver := types.NewMockDIDResolver(ctrl) - mockDockResolver.EXPECT().Resolve(*issuerDID, nil).Return(nil, nil, errors.New("not found")) - mockKeyResolver := crypto.NewMockKeyResolver(ctrl) + mockPubKeyResolver := types.NewMockKeyResolver(ctrl) + mockPubKeyResolver.EXPECT().ResolveKey(*issuerDID, nil, types.NutsSigningKeyType).Return(ssi.URI{}, nil, errors.New("not found")) + mockPrivKeyResolver := crypto.NewMockKeyResolver(ctrl) sut := vdrKeyResolver{ - didResolver: mockDockResolver, - keyResolver: mockKeyResolver, + publicKeyResolver: mockPubKeyResolver, + privateKeyResolver: mockPrivKeyResolver, } key, err := sut.ResolveAssertionKey(ctx, *issuerDID) assert.Nil(t, key) - assert.EqualError(t, err, "not found") + assert.EqualError(t, err, "invalid issuer: not found") }) t.Run("key not found in crypto", func(t *testing.T) { ctrl := gomock.NewController(t) - mockDockResolver := types.NewMockDIDResolver(ctrl) - mockDockResolver.EXPECT().Resolve(*issuerDID, nil).Return(docWithAssertionKey, &types.DocumentMetadata{}, nil) - mockKeyResolver := crypto.NewMockKeyResolver(ctrl) - mockKeyResolver.EXPECT().Resolve(ctx, methodID.String()).Return(nil, errors.New("not found")) + mockPubKeyResolver := types.NewMockKeyResolver(ctrl) + mockPubKeyResolver.EXPECT().ResolveKey(*issuerDID, nil, types.NutsSigningKeyType).Return(methodID.URI(), publicKey, nil) + mockPrivKeyResolver := crypto.NewMockKeyResolver(ctrl) + mockPrivKeyResolver.EXPECT().Resolve(ctx, methodID.String()).Return(nil, errors.New("not found")) sut := vdrKeyResolver{ - didResolver: mockDockResolver, - keyResolver: mockKeyResolver, + publicKeyResolver: mockPubKeyResolver, + privateKeyResolver: mockPrivKeyResolver, } key, err := sut.ResolveAssertionKey(ctx, *issuerDID) assert.Nil(t, key) assert.EqualError(t, err, "failed to resolve assertionKey: could not resolve key from keyStore: not found") }) - - t.Run("did document has no assertionKey", func(t *testing.T) { - ctrl := gomock.NewController(t) - mockDockResolver := types.NewMockDIDResolver(ctrl) - mockDockResolver.EXPECT().Resolve(*issuerDID, nil).Return(&did.Document{}, &types.DocumentMetadata{}, nil) - mockKeyResolver := crypto.NewMockKeyResolver(ctrl) - - sut := vdrKeyResolver{ - didResolver: mockDockResolver, - keyResolver: mockKeyResolver, - } - - key, err := sut.ResolveAssertionKey(ctx, *issuerDID) - assert.Nil(t, key) - assert.EqualError(t, err, "invalid issuer: key not found in DID document") - }) - } diff --git a/vcr/issuer/network_publisher.go b/vcr/issuer/network_publisher.go index abfa53e24d..1432067831 100644 --- a/vcr/issuer/network_publisher.go +++ b/vcr/issuer/network_publisher.go @@ -52,8 +52,8 @@ func NewNetworkPublisher(networkTx network.Transactions, store didstore.Store, k didResolver: didResolver, serviceResolver: didservice.ServiceResolver{Store: store}, keyResolver: vdrKeyResolver{ - didResolver: didResolver, - keyResolver: keyResolver, + publicKeyResolver: didservice.KeyResolver{Store: store}, + privateKeyResolver: keyResolver, }, } diff --git a/vcr/issuer/openid.go b/vcr/issuer/openid.go index e1d214e4c3..d40ae134f6 100644 --- a/vcr/issuer/openid.go +++ b/vcr/issuer/openid.go @@ -321,7 +321,7 @@ func (i *openidHandler) validateProof(ctx context.Context, flow *Flow, request o var signingKeyID string token, err := crypto.ParseJWT(request.Proof.Jwt, func(kid string) (crypt.PublicKey, error) { signingKeyID = kid - return i.keyResolver.ResolveSigningKey(kid, nil) + return i.keyResolver.ResolveKeyByID(kid, nil, types.NutsSigningKeyType) }, jwt.WithAcceptableSkew(5*time.Second)) if err != nil { return generateProofError(openid4vci.Error{ diff --git a/vcr/issuer/openid_test.go b/vcr/issuer/openid_test.go index 37c453ecbc..9805fc59d7 100644 --- a/vcr/issuer/openid_test.go +++ b/vcr/issuer/openid_test.go @@ -123,7 +123,7 @@ func Test_memoryIssuer_HandleCredentialRequest(t *testing.T) { }) ctrl := gomock.NewController(t) keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveSigningKey(keyID, nil).AnyTimes().Return(signerKey.Public(), nil) + keyResolver.EXPECT().ResolveKeyByID(keyID, nil, types.NutsSigningKeyType).AnyTimes().Return(signerKey.Public(), nil) createHeaders := func() map[string]interface{} { return map[string]interface{}{ @@ -265,7 +265,7 @@ func Test_memoryIssuer_HandleCredentialRequest(t *testing.T) { }) t.Run("signing key is unknown", func(t *testing.T) { keyResolver := types.NewMockKeyResolver(ctrl) - keyResolver.EXPECT().ResolveSigningKey(keyID, nil).AnyTimes().Return(nil, types.ErrKeyNotFound) + keyResolver.EXPECT().ResolveKeyByID(keyID, nil, types.NutsSigningKeyType).AnyTimes().Return(nil, types.ErrKeyNotFound) service := requireNewTestHandler(t, keyResolver) _, err := service.createOffer(ctx, issuedVC, preAuthCode) require.NoError(t, err) diff --git a/vcr/store_test.go b/vcr/store_test.go index f984ee8253..bdce82ab0c 100644 --- a/vcr/store_test.go +++ b/vcr/store_test.go @@ -24,6 +24,7 @@ import ( "crypto/sha1" "encoding/json" "github.com/nuts-foundation/nuts-node/crypto/storage/spi" + "github.com/nuts-foundation/nuts-node/vdr/types" "github.com/stretchr/testify/require" "os" "testing" @@ -50,7 +51,7 @@ func TestVcr_StoreCredential(t *testing.T) { t.Run("ok", func(t *testing.T) { ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(gomock.Any(), nil).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), nil, types.NutsSigningKeyType).Return(pk, nil) err := ctx.vcr.StoreCredential(target, nil) @@ -61,7 +62,7 @@ func TestVcr_StoreCredential(t *testing.T) { ctx := newMockContext(t) now := time.Now() - ctx.keyResolver.EXPECT().ResolveSigningKey(gomock.Any(), &now).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), &now, types.NutsSigningKeyType).Return(pk, nil) err := ctx.vcr.StoreCredential(target, &now) @@ -72,7 +73,7 @@ func TestVcr_StoreCredential(t *testing.T) { ctx := newMockContext(t) now := time.Now() - ctx.keyResolver.EXPECT().ResolveSigningKey(gomock.Any(), &now).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), &now, types.NutsSigningKeyType).Return(pk, nil) _ = ctx.vcr.StoreCredential(target, &now) @@ -85,7 +86,7 @@ func TestVcr_StoreCredential(t *testing.T) { ctx := newMockContext(t) now := time.Now() - ctx.keyResolver.EXPECT().ResolveSigningKey(gomock.Any(), &now).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), &now, types.NutsSigningKeyType).Return(pk, nil) _ = ctx.vcr.StoreCredential(target, &now) diff --git a/vcr/verifier/verifier.go b/vcr/verifier/verifier.go index 095927e5f4..b5201a7fba 100644 --- a/vcr/verifier/verifier.go +++ b/vcr/verifier/verifier.go @@ -128,7 +128,7 @@ func (v *verifier) Validate(credentialToVerify vc.VerifiableCredential, at *time } // find key - pk, err := v.keyResolver.ResolveSigningKey(ldProof.VerificationMethod.String(), at) + pk, err := v.keyResolver.ResolveKeyByID(ldProof.VerificationMethod.String(), at, vdr.NutsSigningKeyType) if err != nil { if at == nil { return fmt.Errorf("unable to resolve signing key: %w", err) @@ -239,7 +239,7 @@ func (v *verifier) RegisterRevocation(revocation credential.Revocation) error { return errors.New("verificationMethod should owned by the issuer") } - pk, err := v.keyResolver.ResolveSigningKey(revocation.Proof.VerificationMethod.String(), &revocation.Date) + pk, err := v.keyResolver.ResolveKeyByID(revocation.Proof.VerificationMethod.String(), &revocation.Date, vdr.NutsSigningKeyType) if err != nil { return fmt.Errorf("unable to resolve key for revocation: %w", err) } @@ -283,7 +283,7 @@ func (v verifier) doVerifyVP(vcVerifier Verifier, vp vc.VerifiablePresentation, } // Validate signature - signingKey, err := v.keyResolver.ResolveSigningKey(ldProof.VerificationMethod.String(), validAt) + signingKey, err := v.keyResolver.ResolveKeyByID(ldProof.VerificationMethod.String(), validAt, vdr.NutsSigningKeyType) if err != nil { return nil, fmt.Errorf("unable to resolve valid signing key: %w", err) } diff --git a/vcr/verifier/verifier_test.go b/vcr/verifier/verifier_test.go index 90322ea306..d1eca06a9a 100644 --- a/vcr/verifier/verifier_test.go +++ b/vcr/verifier/verifier_test.go @@ -74,7 +74,7 @@ func Test_verifier_Validate(t *testing.T) { ctx := newMockContext(t) instance := ctx.verifier - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, gomock.Any()).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, gomock.Any(), vdrTypes.NutsSigningKeyType).Return(pk, nil) err := instance.Validate(testCredential(t), nil) @@ -123,7 +123,7 @@ func Test_verifier_Validate(t *testing.T) { vc2 := testCredential(t) vc2.IssuanceDate = time.Now() - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, nil).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, nil, vdrTypes.NutsSigningKeyType).Return(pk, nil) err := instance.Validate(vc2, nil) @@ -139,7 +139,7 @@ func Test_verifier_Validate(t *testing.T) { pr[0].Created = time.Now() vc2.Proof = []interface{}{pr[0]} - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, nil).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, nil, vdrTypes.NutsSigningKeyType).Return(pk, nil) err := instance.Validate(vc2, nil) @@ -159,7 +159,7 @@ func Test_verifier_Validate(t *testing.T) { t.Run("error - wrong jws in proof", func(t *testing.T) { ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, nil).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, nil, vdrTypes.NutsSigningKeyType).Return(pk, nil) instance := ctx.verifier vc2 := testCredential(t) pr := make([]vc.JSONWebSignature2020Proof, 0) @@ -174,7 +174,7 @@ func Test_verifier_Validate(t *testing.T) { t.Run("error - wrong base64 encoding in jws", func(t *testing.T) { ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, nil).Return(pk, nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, nil, vdrTypes.NutsSigningKeyType).Return(pk, nil) instance := ctx.verifier vc2 := testCredential(t) pr := make([]vc.JSONWebSignature2020Proof, 0) @@ -191,7 +191,7 @@ func Test_verifier_Validate(t *testing.T) { ctx := newMockContext(t) instance := ctx.verifier - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, nil).Return(nil, errors.New("b00m!")) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, nil, vdrTypes.NutsSigningKeyType).Return(nil, errors.New("b00m!")) err := instance.Validate(testCredential(t), nil) @@ -231,7 +231,7 @@ func TestVerifier_Verify(t *testing.T) { subject := testCredential(t) subject.IssuanceDate.Add(-1 * time.Minute) - ctx.keyResolver.EXPECT().ResolveSigningKey(testKID, gomock.Any()).Return(nil, errors.New("not found")) + ctx.keyResolver.EXPECT().ResolveKeyByID(testKID, gomock.Any(), vdrTypes.NutsSigningKeyType).Return(nil, errors.New("not found")) at := time.Now() err := instance.Validate(subject, &at) @@ -250,7 +250,7 @@ func TestVerifier_Verify(t *testing.T) { ctx.store.EXPECT().GetRevocations(*vc.ID).Return(nil, ErrNotFound) proofs, _ := vc.Proofs() ctx.didResolver.EXPECT().Resolve(did.MustParseDID(vc.Issuer.String()), gomock.Any()).Return(nil, nil, nil) - ctx.keyResolver.EXPECT().ResolveSigningKey(proofs[0].VerificationMethod.String(), nil).Return(nil, vdrTypes.ErrKeyNotFound) + ctx.keyResolver.EXPECT().ResolveKeyByID(proofs[0].VerificationMethod.String(), nil, vdrTypes.NutsSigningKeyType).Return(nil, vdrTypes.ErrKeyNotFound) validationErr := ctx.verifier.Verify(vc, true, true, nil) @@ -417,7 +417,7 @@ func Test_verifier_CheckAndStoreRevocation(t *testing.T) { t.Run("it checks and stores a valid revocation", func(t *testing.T) { sut := newMockContext(t) - sut.keyResolver.EXPECT().ResolveSigningKey(revocation.Proof.VerificationMethod.String(), &revocation.Date).Return(key, nil) + sut.keyResolver.EXPECT().ResolveKeyByID(revocation.Proof.VerificationMethod.String(), &revocation.Date, vdrTypes.NutsSigningKeyType).Return(key, nil) sut.store.EXPECT().StoreRevocation(revocation) err := sut.verifier.RegisterRevocation(revocation) assert.NoError(t, err) @@ -461,14 +461,14 @@ func Test_verifier_CheckAndStoreRevocation(t *testing.T) { t.Run("it handles an unknown key error", func(t *testing.T) { sut := newMockContext(t) - sut.keyResolver.EXPECT().ResolveSigningKey(revocation.Proof.VerificationMethod.String(), &revocation.Date).Return(nil, errors.New("unknown key")) + sut.keyResolver.EXPECT().ResolveKeyByID(revocation.Proof.VerificationMethod.String(), &revocation.Date, vdrTypes.NutsSigningKeyType).Return(nil, errors.New("unknown key")) err := sut.verifier.RegisterRevocation(revocation) assert.EqualError(t, err, "unable to resolve key for revocation: unknown key") }) t.Run("it handles an error from store operation", func(t *testing.T) { sut := newMockContext(t) - sut.keyResolver.EXPECT().ResolveSigningKey(revocation.Proof.VerificationMethod.String(), &revocation.Date).Return(key, nil) + sut.keyResolver.EXPECT().ResolveKeyByID(revocation.Proof.VerificationMethod.String(), &revocation.Date, vdrTypes.NutsSigningKeyType).Return(key, nil) sut.store.EXPECT().StoreRevocation(revocation).Return(errors.New("storage error")) err := sut.verifier.RegisterRevocation(revocation) assert.EqualError(t, err, "unable to store revocation: storage error") @@ -477,7 +477,7 @@ func Test_verifier_CheckAndStoreRevocation(t *testing.T) { t.Run("it handles an invalid signature error", func(t *testing.T) { sut := newMockContext(t) otherKey := crypto.NewTestKey("did:nuts:123#abc").Public() - sut.keyResolver.EXPECT().ResolveSigningKey(revocation.Proof.VerificationMethod.String(), &revocation.Date).Return(otherKey, nil) + sut.keyResolver.EXPECT().ResolveKeyByID(revocation.Proof.VerificationMethod.String(), &revocation.Date, vdrTypes.NutsSigningKeyType).Return(otherKey, nil) err := sut.verifier.RegisterRevocation(revocation) assert.EqualError(t, err, "unable to verify revocation signature: invalid proof signature: failed to verify signature using ecdsa") }) @@ -535,7 +535,7 @@ func TestVerifier_VerifyVP(t *testing.T) { var validAt *time.Time ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(vpSignerKeyID.String(), validAt).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(vpSignerKeyID.String(), validAt, vdrTypes.NutsSigningKeyType).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) vcs, err := ctx.verifier.VerifyVP(vp, false, validAt) @@ -548,7 +548,7 @@ func TestVerifier_VerifyVP(t *testing.T) { var validAt *time.Time ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(vpSignerKeyID.String(), validAt).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(vpSignerKeyID.String(), validAt, vdrTypes.NutsSigningKeyType).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) mockVerifier := NewMockVerifier(ctx.ctrl) mockVerifier.EXPECT().Verify(vp.VerifiableCredential[0], false, true, validAt) @@ -578,7 +578,7 @@ func TestVerifier_VerifyVP(t *testing.T) { var validAt *time.Time ctx := newMockContext(t) - ctx.keyResolver.EXPECT().ResolveSigningKey(vpSignerKeyID.String(), validAt).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(vpSignerKeyID.String(), validAt, vdrTypes.NutsSigningKeyType).Return(vdr.TestMethodDIDAPrivateKey().Public(), nil) mockVerifier := NewMockVerifier(ctx.ctrl) mockVerifier.EXPECT().Verify(vp.VerifiableCredential[0], false, true, validAt).Return(errors.New("invalid")) @@ -595,7 +595,7 @@ func TestVerifier_VerifyVP(t *testing.T) { ctx := newMockContext(t) // Return incorrect key, causing signature verification failure - ctx.keyResolver.EXPECT().ResolveSigningKey(vpSignerKeyID.String(), validAt).Return(vdr.TestMethodDIDBPrivateKey().Public(), nil) + ctx.keyResolver.EXPECT().ResolveKeyByID(vpSignerKeyID.String(), validAt, vdrTypes.NutsSigningKeyType).Return(vdr.TestMethodDIDBPrivateKey().Public(), nil) vcs, err := ctx.verifier.VerifyVP(vp, false, validAt) @@ -609,7 +609,7 @@ func TestVerifier_VerifyVP(t *testing.T) { ctx := newMockContext(t) // Return incorrect key, causing signature verification failure - ctx.keyResolver.EXPECT().ResolveSigningKey(vpSignerKeyID.String(), validAt).Return(nil, vdrTypes.ErrKeyNotFound) + ctx.keyResolver.EXPECT().ResolveKeyByID(vpSignerKeyID.String(), validAt, vdrTypes.NutsSigningKeyType).Return(nil, vdrTypes.ErrKeyNotFound) vcs, err := ctx.verifier.VerifyVP(vp, false, validAt) diff --git a/vdr/ambassador.go b/vdr/ambassador.go index 883fe35a85..c91af162c6 100644 --- a/vdr/ambassador.go +++ b/vdr/ambassador.go @@ -63,7 +63,7 @@ type ambassador struct { networkClient network.Transactions didStore didstore.Store keyResolver types.NutsKeyResolver - didResolver *didservice.Resolver + didResolver types.DIDResolver eventManager events.Event } diff --git a/vdr/ambassador_test.go b/vdr/ambassador_test.go index 3160bffce7..16fa8e6420 100644 --- a/vdr/ambassador_test.go +++ b/vdr/ambassador_test.go @@ -377,7 +377,7 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { _ = signingKey.Raw(&pKey) ctx.didStore.EXPECT().Resolve(didDocument.ID, &types.ResolveMetadata{AllowDeactivated: true}).Return(&storedDocument, currentMetadata, nil) - ctx.keyStore.EXPECT().ResolvePublicKey(storedDocument.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(storedDocument.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) ctx.didStore.EXPECT().Add(deactivatedDocument, toStoreTX(tx)) err = ctx.ambassador.handleUpdateDIDDocument(tx, deactivatedDocument) @@ -413,8 +413,8 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { _ = signingKey.Raw(&pKey) ctx.didStore.EXPECT().Resolve(didDocument.ID, &types.ResolveMetadata{AllowDeactivated: true}).Return(&expectedDocument, currentMetadata, nil) - ctx.didStore.EXPECT().Resolve(controllerDoc.ID, &types.ResolveMetadata{ResolveTime: &tx.signingTime}).Return(&controllerDoc, nil, nil) - ctx.keyStore.EXPECT().ResolvePublicKey(controllerDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) + ctx.didResolver.EXPECT().Resolve(controllerDoc.ID, gomock.Any()).Return(&controllerDoc, currentMetadata, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(controllerDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) ctx.didStore.EXPECT().Add(expectedDocument, toStoreTX(tx)) err := ctx.ambassador.handleUpdateDIDDocument(tx, expectedDocument) @@ -449,7 +449,7 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { _ = signingKey.Raw(&pKey) ctx.didStore.EXPECT().Resolve(currentDoc.ID, &types.ResolveMetadata{AllowDeactivated: true, SourceTransaction: &prev}).Return(¤tDoc, currentMetadata, nil) - ctx.keyStore.EXPECT().ResolvePublicKey(currentDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(currentDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) ctx.didStore.EXPECT().Add(newDoc, toStoreTX(tx)) err := ctx.ambassador.handleUpdateDIDDocument(tx, newDoc) @@ -487,7 +487,7 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { ctx.didStore.EXPECT().Resolve(currentDoc.ID, gomock.Any()).Return(nil, nil, types.ErrNotFound), ctx.didStore.EXPECT().Resolve(currentDoc.ID, &types.ResolveMetadata{AllowDeactivated: true, SourceTransaction: &prev}).Return(¤tDoc, currentMetadata, nil), ) - ctx.keyStore.EXPECT().ResolvePublicKey(currentDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(currentDoc.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) ctx.didStore.EXPECT().Add(newDoc, toStoreTX(tx)) err := ctx.ambassador.handleUpdateDIDDocument(tx, newDoc) @@ -541,8 +541,8 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { } ctx.didStore.EXPECT().Resolve(didDocument.ID, &types.ResolveMetadata{AllowDeactivated: true}).Return(&expectedDocument, currentMetadata, nil) - ctx.didStore.EXPECT().Resolve(didDocumentController.ID, gomock.Any()).Return(&didDocumentController, currentMetadata, nil) - ctx.keyStore.EXPECT().ResolvePublicKey(didDocumentController.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) + ctx.didResolver.EXPECT().Resolve(didDocumentController.ID, gomock.Any()).Return(&didDocumentController, currentMetadata, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(didDocumentController.CapabilityInvocation[0].ID.String(), gomock.Any()).Return(pKey, nil) ctx.didStore.EXPECT().Add(expectedDocument, toStoreTX(tx)) err = ctx.ambassador.handleUpdateDIDDocument(tx, expectedDocument) @@ -602,8 +602,8 @@ func TestAmbassador_handleUpdateDIDDocument(t *testing.T) { } ctx.didStore.EXPECT().Resolve(didDocument.ID, &types.ResolveMetadata{AllowDeactivated: true}).Return(&expectedDocument, currentMetadata, nil) - ctx.didStore.EXPECT().Resolve(didDocumentController.ID, &types.ResolveMetadata{ResolveTime: &tx.signingTime}).Return(&didDocumentController, currentMetadata, nil) - ctx.keyStore.EXPECT().ResolvePublicKey(keyID, gomock.Any()).Return(pKey, nil) + ctx.didResolver.EXPECT().Resolve(didDocumentController.ID, gomock.Any()).Return(&didDocumentController, currentMetadata, nil) + ctx.keyResolver.EXPECT().ResolvePublicKey(keyID, gomock.Any()).Return(pKey, nil) err = ctx.ambassador.handleUpdateDIDDocument(tx, didDocument) assert.EqualError(t, err, "network document not signed by one of its controllers") @@ -624,7 +624,7 @@ func Test_handleUpdateDIDDocument(t *testing.T) { ctrl := gomock.NewController(t) didStoreMock := didstore.NewMockStore(ctrl) - keyStoreMock := types.NewMockKeyResolver(ctrl) + keyStoreMock := types.NewMockNutsKeyResolver(ctrl) didResolver := &didservice.Resolver{Store: didStoreMock} am := ambassador{ @@ -827,7 +827,8 @@ func newDidDoc() (did.Document, jwk.Key, error) { type mockContext struct { ctrl *gomock.Controller didStore *didstore.MockStore - keyStore *types.MockKeyResolver + keyResolver *types.MockNutsKeyResolver + didResolver *types.MockDIDResolver eventManager *events.MockEvent network *network.MockTransactions ambassador ambassador @@ -836,13 +837,14 @@ type mockContext struct { func newMockContext(t *testing.T) mockContext { ctrl := gomock.NewController(t) didStoreMock := didstore.NewMockStore(ctrl) - keyStoreMock := types.NewMockKeyResolver(ctrl) + keyResolverMock := types.NewMockNutsKeyResolver(ctrl) + resolverMock := types.NewMockDIDResolver(ctrl) eventManager := events.NewMockEvent(ctrl) networkMock := network.NewMockTransactions(ctrl) am := ambassador{ didStore: didStoreMock, - didResolver: &didservice.Resolver{Store: didStoreMock}, - keyResolver: keyStoreMock, + didResolver: resolverMock, + keyResolver: keyResolverMock, eventManager: eventManager, networkClient: networkMock, } @@ -850,7 +852,8 @@ func newMockContext(t *testing.T) mockContext { return mockContext{ ctrl: ctrl, didStore: didStoreMock, - keyStore: keyStoreMock, + keyResolver: keyResolverMock, + didResolver: resolverMock, ambassador: am, eventManager: eventManager, network: networkMock, diff --git a/vdr/didservice/nuts_resolvers.go b/vdr/didservice/nuts_resolvers.go new file mode 100644 index 0000000000..b49389becb --- /dev/null +++ b/vdr/didservice/nuts_resolvers.go @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 Nuts community + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package didservice + +import ( + "crypto" + "github.com/nuts-foundation/nuts-node/crypto/hash" + "github.com/nuts-foundation/nuts-node/vdr/types" +) + +// NutsKeyResolver implements the NutsKeyResolver interface. +type NutsKeyResolver struct { + Resolver types.DIDResolver +} + +func (r NutsKeyResolver) ResolvePublicKey(kid string, sourceTransactionsRefs []hash.SHA256Hash) (crypto.PublicKey, error) { + // try all keys, continue when err == types.ErrNotFound + for _, h := range sourceTransactionsRefs { + publicKey, err := resolvePublicKey(r.Resolver, kid, types.ResolveMetadata{ + SourceTransaction: &h, + }) + if err == nil { + return publicKey, nil + } + if err != types.ErrNotFound { + return nil, err + } + } + + return nil, types.ErrNotFound +} diff --git a/vdr/didservice/nuts_resolvers_test.go b/vdr/didservice/nuts_resolvers_test.go new file mode 100644 index 0000000000..fdbdf840fd --- /dev/null +++ b/vdr/didservice/nuts_resolvers_test.go @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Nuts community + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package didservice + +import ( + "github.com/nuts-foundation/nuts-node/crypto/hash" + "github.com/nuts-foundation/nuts-node/vdr/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + "testing" +) + +func TestNutsKeyResolver_ResolvePublicKey(t *testing.T) { + ctrl := gomock.NewController(t) + didResolver := types.NewMockDIDResolver(ctrl) + keyResolver := NutsKeyResolver{Resolver: didResolver} + keyCreator := newMockKeyCreator() + docCreator := Creator{KeyStore: keyCreator} + doc, _, _ := docCreator.Create(nil, DefaultCreationOptions()) + + t.Run("ok by hash", func(t *testing.T) { + didResolver.EXPECT().Resolve(testDID, gomock.Any()).Do(func(arg0 interface{}, arg1 interface{}) { + resolveMetadata := arg1.(*types.ResolveMetadata) + assert.Equal(t, hash.EmptyHash(), *resolveMetadata.SourceTransaction) + }).Return(doc, nil, nil) + + key, err := keyResolver.ResolvePublicKey(mockKID, []hash.SHA256Hash{hash.EmptyHash()}) + require.NoError(t, err) + + assert.NotNil(t, key) + }) + +} diff --git a/vdr/didservice/resolvers.go b/vdr/didservice/resolvers.go index 2322de6a13..aa836c8078 100644 --- a/vdr/didservice/resolvers.go +++ b/vdr/didservice/resolvers.go @@ -23,7 +23,6 @@ import ( "crypto" "errors" "fmt" - "github.com/nuts-foundation/nuts-node/crypto/hash" "github.com/nuts-foundation/nuts-node/vdr/didstore" "time" @@ -129,54 +128,14 @@ func resolveControllers(resolver types.DIDResolver, doc did.Document, metadata * return leaves[:j], nil } -// NutsKeyResolver implements the NutsKeyResolver interface. -type NutsKeyResolver struct { - Resolver types.DIDResolver -} - -func (r NutsKeyResolver) ResolvePublicKey(kid string, sourceTransactionsRefs []hash.SHA256Hash) (crypto.PublicKey, error) { - // try all keys, continue when err == types.ErrNotFound - for _, h := range sourceTransactionsRefs { - publicKey, err := r.resolvePublicKey(r.Resolver, kid, types.ResolveMetadata{ - SourceTransaction: &h, - }) - if err == nil { - return publicKey, nil - } - if err != types.ErrNotFound { - return nil, err - } - } - - return nil, types.ErrNotFound -} +var _ types.KeyResolver = KeyResolver{} // KeyResolver implements the KeyResolver interface with a types.Store as backend type KeyResolver struct { Store didstore.Store } -// ResolveSigningKeyID resolves the ID of the first valid AssertionMethod for an indicated DID document at a given time. -func (r KeyResolver) ResolveSigningKeyID(holder did.DID, validAt *time.Time) (string, error) { - doc, _, err := r.Store.Resolve(holder, &types.ResolveMetadata{ - ResolveTime: validAt, - }) - if err != nil { - return "", err - } - if len(doc.AssertionMethod) == 0 { - return "", types.ErrKeyNotFound - } - return doc.AssertionMethod[0].ID.String(), nil -} - -// ResolveSigningKey resolves the PublicKey of the first valid AssertionMethod for an indicated -// DID document at a validAt time. -func (r KeyResolver) ResolveSigningKey(keyID string, validAt *time.Time) (crypto.PublicKey, error) { - return r.ResolveRelationKey(keyID, validAt, types.AssertionMethod) -} - -func (r KeyResolver) ResolveRelationKey(keyID string, validAt *time.Time, relationType types.RelationType) (crypto.PublicKey, error) { +func (r KeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType types.RelationType) (crypto.PublicKey, error) { holder, err := GetDIDFromURL(keyID) if err != nil { return nil, fmt.Errorf("invalid key ID (id=%s): %w", keyID, err) @@ -185,16 +144,39 @@ func (r KeyResolver) ResolveRelationKey(keyID string, validAt *time.Time, relati ResolveTime: validAt, }) if err != nil { - return "", err + return nil, err + } + relationships, err := resolveRelationships(doc, relationType) + if err != nil { + return nil, err } - relationships, _ := resolveRelationships(doc, relationType) - for _, rel := range relationships { if rel.ID.String() == keyID { return rel.PublicKey() } } - return "", types.ErrKeyNotFound + return nil, types.ErrKeyNotFound +} + +func (r KeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType types.RelationType) (ssi.URI, crypto.PublicKey, error) { + doc, _, err := r.Store.Resolve(id, &types.ResolveMetadata{ + ResolveTime: validAt, + }) + if err != nil { + return ssi.URI{}, nil, err + } + keys, err := resolveRelationships(doc, relationType) + if err != nil { + return ssi.URI{}, nil, err + } + if len(keys) == 0 { + return ssi.URI{}, nil, types.ErrKeyNotFound + } + publicKey, err := keys[0].PublicKey() + if err != nil { + return ssi.URI{}, nil, err + } + return keys[0].ID.URI(), publicKey, nil } func resolveRelationships(doc *did.Document, relationType types.RelationType) (relationships did.VerificationRelationships, err error) { @@ -213,56 +195,7 @@ func resolveRelationships(doc *did.Document, relationType types.RelationType) (r return nil, fmt.Errorf("unable to locate RelationType %v", relationType) } } - -// ResolveAssertionKeyID resolves the id of the first valid AssertionMethod of an indicated DID document in the current state. -func (r KeyResolver) ResolveAssertionKeyID(id did.DID) (ssi.URI, error) { - doc, _, err := r.Store.Resolve(id, nil) - if err != nil { - return ssi.URI{}, err - } - - return ExtractFirstRelationKeyIDByType(*doc, types.AssertionMethod) -} - -func (r KeyResolver) ResolveRelationKeyID(id did.DID, relationType types.RelationType) (ssi.URI, error) { - doc, _, err := r.Store.Resolve(id, nil) - if err != nil { - return ssi.URI{}, err - } - - return ExtractFirstRelationKeyIDByType(*doc, relationType) -} - -// ResolveKeyAgreementKey resolves the public key of the first valid KeyAgreement of an indicated DID document in the current state. -// If the document has no KeyAgreements, types.ErrKeyNotFound is returned. -func (r KeyResolver) ResolveKeyAgreementKey(id did.DID) (crypto.PublicKey, error) { - doc, _, err := r.Store.Resolve(id, nil) - if err != nil { - return ssi.URI{}, err - } - if len(doc.KeyAgreement) == 0 { - return nil, types.ErrKeyNotFound - } - return doc.KeyAgreement[0].PublicKey() -} - -// ExtractFirstRelationKeyIDByType returns the first relation key ID from the given DID document matching the relationType. -// Returns a types.ErrKeyNotFound if no relation key of the given relationType is present. -func ExtractFirstRelationKeyIDByType(doc did.Document, relationType types.RelationType) (ssi.URI, error) { - keys, err := resolveRelationships(&doc, relationType) - if err != nil { - return ssi.URI{}, err - } - for _, key := range keys { - kid := key.ID.String() - u, _ := ssi.ParseURI(kid) - return *u, nil - } - - return ssi.URI{}, types.ErrKeyNotFound -} - -func (r NutsKeyResolver) resolvePublicKey(resolver types.DIDResolver, kid string, metadata types.ResolveMetadata) (crypto.PublicKey, error) { +func resolvePublicKey(resolver types.DIDResolver, kid string, metadata types.ResolveMetadata) (crypto.PublicKey, error) { id, err := did.ParseDIDURL(kid) if err != nil { return nil, fmt.Errorf("invalid key ID (id=%s): %w", kid, err) diff --git a/vdr/didservice/resolvers_test.go b/vdr/didservice/resolvers_test.go index 97db93baf1..2a0ada5fe8 100644 --- a/vdr/didservice/resolvers_test.go +++ b/vdr/didservice/resolvers_test.go @@ -20,7 +20,6 @@ package didservice import ( "errors" "fmt" - "github.com/nuts-foundation/nuts-node/audit" "testing" "time" @@ -34,177 +33,6 @@ import ( "go.uber.org/mock/gomock" ) -func TestResolveSigningKey(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - keyCreator := newMockKeyCreator() - docCreator := Creator{KeyStore: keyCreator} - doc, _, _ := docCreator.Create(nil, DefaultCreationOptions()) - // add a second key to the document - methodID := doc.ID - methodID.Fragment = "key2" - newMethod := &did.VerificationMethod{ID: methodID} - doc.AddAssertionMethod(newMethod) - - t.Run("ok", func(t *testing.T) { - store.EXPECT().Resolve(testDID, gomock.Any()).Return(doc, nil, nil) - - key, err := keyResolver.ResolveSigningKey(mockKID, nil) - - require.NoError(t, err) - assert.NotNil(t, key) - }) - - t.Run("unable to resolve document", func(t *testing.T) { - store.EXPECT().Resolve(testDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) - - _, err := keyResolver.ResolveSigningKey(mockKID, nil) - - assert.Error(t, err) - assert.Equal(t, types.ErrNotFound, err) - }) - - t.Run("signing key not found in document", func(t *testing.T) { - store.EXPECT().Resolve(testDID, gomock.Any()).Return(doc, nil, nil) - - _, err := keyResolver.ResolveSigningKey(mockKID[:len(mockKID)-2], nil) - - assert.Error(t, err) - assert.Equal(t, types.ErrKeyNotFound, err) - }) - - t.Run("invalid key ID", func(t *testing.T) { - _, err := keyResolver.ResolveSigningKey("asdasdsa", nil) - - assert.Error(t, err) - assert.ErrorIs(t, err, did.ErrInvalidDID) - }) -} - -func TestResolveSigningKeyID(t *testing.T) { - keyCreator := newMockKeyCreator() - docCreator := Creator{KeyStore: keyCreator} - doc, _, _ := docCreator.Create(nil, DefaultCreationOptions()) - - t.Run("ok", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(doc, nil, nil) - - actual, err := keyResolver.ResolveSigningKeyID(testDID, nil) - - require.NoError(t, err) - assert.Equal(t, mockKID, actual) - }) - - t.Run("unable to resolve", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) - - _, err := keyResolver.ResolveSigningKeyID(testDID, nil) - - assert.Error(t, err) - assert.Equal(t, types.ErrNotFound, err) - }) - - t.Run("signing key not found", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(&did.Document{}, nil, nil) - - _, err := keyResolver.ResolveSigningKeyID(testDID, nil) - - assert.Equal(t, types.ErrKeyNotFound, err) - }) -} - -func TestKeyResolver_ResolveAssertionKeyID(t *testing.T) { - keyCreator := newMockKeyCreator() - docCreator := Creator{KeyStore: keyCreator} - doc, _, _ := docCreator.Create(nil, DefaultCreationOptions()) - - t.Run("ok - resolve a known key", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(doc, nil, nil) - - actual, err := keyResolver.ResolveAssertionKeyID(testDID) - - require.NoError(t, err) - assert.Equal(t, mockKID, actual.String()) - }) - - t.Run("unable to resolve", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) - - _, err := keyResolver.ResolveAssertionKeyID(testDID) - - assert.Error(t, err) - assert.Equal(t, types.ErrNotFound, err) - }) - - t.Run("signing key not found", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(&did.Document{}, nil, nil) - - _, err := keyResolver.ResolveAssertionKeyID(testDID) - - assert.Equal(t, types.ErrKeyNotFound, err) - }) -} - -func TestKeyResolver_ResolveKeyAgreementKey(t *testing.T) { - keyCreator := newMockKeyCreator() - docCreator := Creator{KeyStore: keyCreator} - doc, _, _ := docCreator.Create(audit.TestContext(), DefaultCreationOptions()) - - t.Run("ok - resolve a known key", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(doc, nil, nil) - - actual, err := keyResolver.ResolveKeyAgreementKey(testDID) - - require.NoError(t, err) - assert.NotNil(t, actual) - }) - - t.Run("unable to resolve", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) - - _, err := keyResolver.ResolveKeyAgreementKey(testDID) - - assert.Error(t, err) - assert.Equal(t, types.ErrNotFound, err) - }) - - t.Run("key not found", func(t *testing.T) { - ctrl := gomock.NewController(t) - store := didstore.NewMockStore(ctrl) - keyResolver := KeyResolver{Store: store} - store.EXPECT().Resolve(testDID, gomock.Any()).Return(&did.Document{}, nil, nil) - - _, err := keyResolver.ResolveKeyAgreementKey(testDID) - - assert.Equal(t, types.ErrKeyNotFound, err) - }) -} - func TestResolver_Resolve(t *testing.T) { id123, _ := did.ParseDID("did:nuts:123") id456, _ := did.ParseDID("did:nuts:456") @@ -452,28 +280,6 @@ func TestResolveControllers(t *testing.T) { }) } -func TestNutsKeyResolver_ResolvePublicKey(t *testing.T) { - ctrl := gomock.NewController(t) - didResolver := types.NewMockDIDResolver(ctrl) - keyResolver := NutsKeyResolver{Resolver: didResolver} - keyCreator := newMockKeyCreator() - docCreator := Creator{KeyStore: keyCreator} - doc, _, _ := docCreator.Create(nil, DefaultCreationOptions()) - - t.Run("ok by hash", func(t *testing.T) { - didResolver.EXPECT().Resolve(testDID, gomock.Any()).Do(func(arg0 interface{}, arg1 interface{}) { - resolveMetadata := arg1.(*types.ResolveMetadata) - assert.Equal(t, hash.EmptyHash(), *resolveMetadata.SourceTransaction) - }).Return(doc, nil, nil) - - key, err := keyResolver.ResolvePublicKey(mockKID, []hash.SHA256Hash{hash.EmptyHash()}) - require.NoError(t, err) - - assert.NotNil(t, key) - }) - -} - func TestServiceResolver_Resolve(t *testing.T) { meta := &types.DocumentMetadata{Hash: hash.EmptyHash()} @@ -583,62 +389,49 @@ func TestServiceResolver_Resolve(t *testing.T) { } -func TestExtractFirstRelationKeyIDByType(t *testing.T) { +func TestKeyResolver_ResolveKey(t *testing.T) { + ctrl := gomock.NewController(t) + store := didstore.NewMockStore(ctrl) + keyResolver := KeyResolver{Store: store} + keyCreator := newMockKeyCreator() docCreator := Creator{KeyStore: keyCreator} doc, _, err := docCreator.Create(nil, DefaultCreationOptions()) require.NoError(t, err) - type args struct { - doc did.Document - relationType types.RelationType - } - tests := []struct { - name string - args args - want ssi.URI - expectedErr error - }{ - { - name: "ok - it finds the key", - args: args{ - doc: *doc, - relationType: types.AssertionMethod, - }, - want: doc.VerificationMethod[0].ID.URI(), - expectedErr: nil, - }, - { - name: "err - key not found", - args: args{ - doc: *doc, - relationType: types.CapabilityDelegation, - }, - want: ssi.URI{}, - expectedErr: types.ErrKeyNotFound, - }, - { - name: "err - unknown relation type", - args: args{ - doc: *doc, - relationType: 20, - }, - want: ssi.URI{}, - expectedErr: errors.New("unable to locate RelationType 20"), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ExtractFirstRelationKeyIDByType(tt.args.doc, tt.args.relationType) - if tt.expectedErr != nil { - require.EqualError(t, err, tt.expectedErr.Error()) - return - } - assert.Equalf(t, tt.want, got, "ExtractFirstRelationKeyIDByType(%v, %v)", tt.args.doc, tt.args.relationType) - }) - } + store.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(doc, nil, nil) + + t.Run("ok - it finds the key", func(t *testing.T) { + keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, types.AssertionMethod) + require.NoError(t, err) + assert.Equal(t, doc.VerificationMethod[0].ID.URI(), keyId) + assert.NotNil(t, key) + }) + + t.Run("error - document not found", func(t *testing.T) { + unknownDID := did.MustParseDID("did:example:123") + store.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) + keyId, key, err := keyResolver.ResolveKey(unknownDID, nil, types.AssertionMethod) + assert.EqualError(t, err, "unable to find the DID document") + assert.Empty(t, keyId) + assert.Nil(t, key) + }) + + t.Run("error - key not found", func(t *testing.T) { + keyId, key, err := keyResolver.ResolveKey(did.MustParseDIDURL(doc.ID.String()), nil, types.CapabilityDelegation) + assert.EqualError(t, err, "key not found in DID document") + assert.Empty(t, keyId) + assert.Nil(t, key) + }) + + t.Run("error - unknown relationship type", func(t *testing.T) { + keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, 1000) + assert.EqualError(t, err, "unable to locate RelationType 1000") + assert.Empty(t, keyId) + assert.Nil(t, key) + }) } -func TestKeyResolver_ResolveRelationKeyID(t *testing.T) { +func TestKeyResolver_ResolveKeyByID(t *testing.T) { ctrl := gomock.NewController(t) store := didstore.NewMockStore(ctrl) keyResolver := KeyResolver{Store: store} @@ -646,21 +439,40 @@ func TestKeyResolver_ResolveRelationKeyID(t *testing.T) { keyCreator := newMockKeyCreator() docCreator := Creator{KeyStore: keyCreator} doc, _, err := docCreator.Create(nil, DefaultCreationOptions()) - store.EXPECT().Resolve(doc.ID, gomock.Any()).Return(doc, nil, nil) require.NoError(t, err) + store.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(doc, nil, nil) + keyID := doc.VerificationMethod[0].ID t.Run("ok - it finds the key", func(t *testing.T) { - keyId, err := keyResolver.ResolveRelationKeyID(doc.ID, types.AssertionMethod) - require.NoError(t, err) - assert.Equal(t, doc.VerificationMethod[0].ID.URI(), keyId) + key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, types.AssertionMethod) + assert.NoError(t, err) + assert.NotNil(t, key) }) - t.Run("err - document not found", func(t *testing.T) { - unknownDID := did.MustParseDID("did:example:123") + t.Run("error - invalid key ID", func(t *testing.T) { + key, err := keyResolver.ResolveKeyByID("abcdef", nil, types.AssertionMethod) + assert.EqualError(t, err, "invalid key ID (id=abcdef): invalid DID") + assert.Nil(t, key) + }) + + t.Run("error - document not found", func(t *testing.T) { + unknownDID := did.MustParseDIDURL("did:example:123") store.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, types.ErrNotFound) - keyId, err := keyResolver.ResolveRelationKeyID(unknownDID, types.AssertionMethod) - require.EqualError(t, err, "unable to find the DID document") - require.Equal(t, ssi.URI{}, keyId) + key, err := keyResolver.ResolveKeyByID(unknownDID.String()+"#456", nil, types.AssertionMethod) + assert.EqualError(t, err, "unable to find the DID document") + assert.Nil(t, key) + }) + + t.Run("error - key not found", func(t *testing.T) { + key, err := keyResolver.ResolveKeyByID(did.MustParseDIDURL(doc.ID.String()+"#123").String(), nil, types.AssertionMethod) + assert.EqualError(t, err, "key not found in DID document") + assert.Nil(t, key) + }) + + t.Run("error - unknown relationship type", func(t *testing.T) { + key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, 1000) + assert.EqualError(t, err, "unable to locate RelationType 1000") + assert.Nil(t, key) }) } diff --git a/vdr/integration_test.go b/vdr/integration_test.go index 82482f9aae..3dcff7ba78 100644 --- a/vdr/integration_test.go +++ b/vdr/integration_test.go @@ -97,7 +97,7 @@ func TestVDRIntegration_Test(t *testing.T) { "unexpected error while resolving documentB") // Update the controller of DocumentA with DocumentB - // And remove it's own authenticationMethod + // And remove its own authenticationMethod docA.Controller = []did.DID{docB.ID} docA.AssertionMethod = []did.VerificationRelationship{} docA.CapabilityInvocation = []did.VerificationRelationship{} diff --git a/vdr/types/interface.go b/vdr/types/interface.go index 9e122043c4..bb2f12a47f 100644 --- a/vdr/types/interface.go +++ b/vdr/types/interface.go @@ -79,28 +79,19 @@ type DocUpdater interface { // KeyResolver is the interface for resolving keys. // This can be used for checking if a signing key is valid at a point in time or to just find a valid key for signing. type KeyResolver interface { - // ResolveSigningKeyID looks up a signing key of the specified holder. It returns the ID - // of the found key. Typically used to find a key for signing one's own documents. If no suitable keys - // are found an error is returned. - ResolveSigningKeyID(holder did.DID, validAt *time.Time) (string, error) - // ResolveSigningKey looks up a specific signing key and returns it as crypto.PublicKey. If the key can't be found - // or isn't meant for signing an error is returned. - ResolveSigningKey(keyID string, validAt *time.Time) (crypto.PublicKey, error) - // ResolveAssertionKeyID look for a valid assertion key for the give DID. If multiple keys are valid, the first one is returned. - // An ErrKeyNotFound is returned when no key is found. - ResolveAssertionKeyID(id did.DID) (ssi.URI, error) - // ResolveKeyAgreementKey look for a valid keyAgreement key for the give DID. If multiple keys are valid, the first one is returned. - // An ErrKeyNotFound is returned when no key is found. - ResolveKeyAgreementKey(id did.DID) (crypto.PublicKey, error) - // ResolveRelationKey looks up a specific key of the given RelationType and returns it as crypto.PublicKey. - // If the key can't be found or isn't meant for signing an error is returned. - ResolveRelationKey(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) - // ResolveRelationKeyID look for a valid key of the given RelationType for the give DID. + // ResolveKeyByID looks up a specific key of the given RelationType and returns it as crypto.PublicKey. // If multiple keys are valid, the first one is returned. - // An ErrKeyNotFound is returned when no key is found. - ResolveRelationKeyID(id did.DID, relationType RelationType) (ssi.URI, error) + // An ErrKeyNotFound is returned when no key (of the specified type) is found. + ResolveKeyByID(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) + // ResolveKey looks for a valid key of the given RelationType for the given DID, and returns its ID and the key itself. + // If multiple keys are valid, the first one is returned. + // An ErrKeyNotFound is returned when no key (of the specified type) is found. + ResolveKey(id did.DID, validAt *time.Time, relationType RelationType) (ssi.URI, crypto.PublicKey, error) } +// NutsSigningKeyType defines the verification method relationship type for signing keys in Nuts DID Documents. +const NutsSigningKeyType = AssertionMethod + // NutsKeyResolver is the interface for resolving keys from Nuts DID Documents, // supporting Nuts-specific DID resolution parameters. type NutsKeyResolver interface { diff --git a/vdr/types/mock.go b/vdr/types/mock.go index d6fe1730ea..8ed6320ca5 100644 --- a/vdr/types/mock.go +++ b/vdr/types/mock.go @@ -271,109 +271,73 @@ func (m *MockKeyResolver) EXPECT() *MockKeyResolverMockRecorder { return m.recorder } -// ResolveAssertionKeyID mocks base method. -func (m *MockKeyResolver) ResolveAssertionKeyID(id did.DID) (ssi.URI, error) { +// ResolveKey mocks base method. +func (m *MockKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType RelationType) (ssi.URI, crypto.PublicKey, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveAssertionKeyID", id) + ret := m.ctrl.Call(m, "ResolveKey", id, validAt, relationType) ret0, _ := ret[0].(ssi.URI) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(crypto.PublicKey) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } -// ResolveAssertionKeyID indicates an expected call of ResolveAssertionKeyID. -func (mr *MockKeyResolverMockRecorder) ResolveAssertionKeyID(id interface{}) *gomock.Call { +// ResolveKey indicates an expected call of ResolveKey. +func (mr *MockKeyResolverMockRecorder) ResolveKey(id, validAt, relationType interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveAssertionKeyID", reflect.TypeOf((*MockKeyResolver)(nil).ResolveAssertionKeyID), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveKey", reflect.TypeOf((*MockKeyResolver)(nil).ResolveKey), id, validAt, relationType) } -// ResolveKeyAgreementKey mocks base method. -func (m *MockKeyResolver) ResolveKeyAgreementKey(id did.DID) (crypto.PublicKey, error) { +// ResolveKeyByID mocks base method. +func (m *MockKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveKeyAgreementKey", id) + ret := m.ctrl.Call(m, "ResolveKeyByID", keyID, validAt, relationType) ret0, _ := ret[0].(crypto.PublicKey) ret1, _ := ret[1].(error) return ret0, ret1 } -// ResolveKeyAgreementKey indicates an expected call of ResolveKeyAgreementKey. -func (mr *MockKeyResolverMockRecorder) ResolveKeyAgreementKey(id interface{}) *gomock.Call { +// ResolveKeyByID indicates an expected call of ResolveKeyByID. +func (mr *MockKeyResolverMockRecorder) ResolveKeyByID(keyID, validAt, relationType interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveKeyAgreementKey", reflect.TypeOf((*MockKeyResolver)(nil).ResolveKeyAgreementKey), id) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveKeyByID", reflect.TypeOf((*MockKeyResolver)(nil).ResolveKeyByID), keyID, validAt, relationType) } -// ResolvePublicKey mocks base method. -func (m *MockKeyResolver) ResolvePublicKey(kid string, sourceTransactionsRefs []hash.SHA256Hash) (crypto.PublicKey, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolvePublicKey", kid, sourceTransactionsRefs) - ret0, _ := ret[0].(crypto.PublicKey) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ResolvePublicKey indicates an expected call of ResolvePublicKey. -func (mr *MockKeyResolverMockRecorder) ResolvePublicKey(kid, sourceTransactionsRefs interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolvePublicKey", reflect.TypeOf((*MockKeyResolver)(nil).ResolvePublicKey), kid, sourceTransactionsRefs) +// MockNutsKeyResolver is a mock of NutsKeyResolver interface. +type MockNutsKeyResolver struct { + ctrl *gomock.Controller + recorder *MockNutsKeyResolverMockRecorder } -// ResolveRelationKey mocks base method. -func (m *MockKeyResolver) ResolveRelationKey(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveRelationKey", keyID, validAt, relationType) - ret0, _ := ret[0].(crypto.PublicKey) - ret1, _ := ret[1].(error) - return ret0, ret1 +// MockNutsKeyResolverMockRecorder is the mock recorder for MockNutsKeyResolver. +type MockNutsKeyResolverMockRecorder struct { + mock *MockNutsKeyResolver } -// ResolveRelationKey indicates an expected call of ResolveRelationKey. -func (mr *MockKeyResolverMockRecorder) ResolveRelationKey(keyID, validAt, relationType interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelationKey", reflect.TypeOf((*MockKeyResolver)(nil).ResolveRelationKey), keyID, validAt, relationType) -} - -// ResolveRelationKeyID mocks base method. -func (m *MockKeyResolver) ResolveRelationKeyID(id did.DID, relationType RelationType) (ssi.URI, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveRelationKeyID", id, relationType) - ret0, _ := ret[0].(ssi.URI) - ret1, _ := ret[1].(error) - return ret0, ret1 +// NewMockNutsKeyResolver creates a new mock instance. +func NewMockNutsKeyResolver(ctrl *gomock.Controller) *MockNutsKeyResolver { + mock := &MockNutsKeyResolver{ctrl: ctrl} + mock.recorder = &MockNutsKeyResolverMockRecorder{mock} + return mock } -// ResolveRelationKeyID indicates an expected call of ResolveRelationKeyID. -func (mr *MockKeyResolverMockRecorder) ResolveRelationKeyID(id, relationType interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveRelationKeyID", reflect.TypeOf((*MockKeyResolver)(nil).ResolveRelationKeyID), id, relationType) +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockNutsKeyResolver) EXPECT() *MockNutsKeyResolverMockRecorder { + return m.recorder } -// ResolveSigningKey mocks base method. -func (m *MockKeyResolver) ResolveSigningKey(keyID string, validAt *time.Time) (crypto.PublicKey, error) { +// ResolvePublicKey mocks base method. +func (m *MockNutsKeyResolver) ResolvePublicKey(kid string, sourceTransactionsRefs []hash.SHA256Hash) (crypto.PublicKey, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveSigningKey", keyID, validAt) + ret := m.ctrl.Call(m, "ResolvePublicKey", kid, sourceTransactionsRefs) ret0, _ := ret[0].(crypto.PublicKey) ret1, _ := ret[1].(error) return ret0, ret1 } -// ResolveSigningKey indicates an expected call of ResolveSigningKey. -func (mr *MockKeyResolverMockRecorder) ResolveSigningKey(keyID, validAt interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveSigningKey", reflect.TypeOf((*MockKeyResolver)(nil).ResolveSigningKey), keyID, validAt) -} - -// ResolveSigningKeyID mocks base method. -func (m *MockKeyResolver) ResolveSigningKeyID(holder did.DID, validAt *time.Time) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResolveSigningKeyID", holder, validAt) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ResolveSigningKeyID indicates an expected call of ResolveSigningKeyID. -func (mr *MockKeyResolverMockRecorder) ResolveSigningKeyID(holder, validAt interface{}) *gomock.Call { +// ResolvePublicKey indicates an expected call of ResolvePublicKey. +func (mr *MockNutsKeyResolverMockRecorder) ResolvePublicKey(kid, sourceTransactionsRefs interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolveSigningKeyID", reflect.TypeOf((*MockKeyResolver)(nil).ResolveSigningKeyID), holder, validAt) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResolvePublicKey", reflect.TypeOf((*MockNutsKeyResolver)(nil).ResolvePublicKey), kid, sourceTransactionsRefs) } // MockVDR is a mock of VDR interface.