From ef4be53bcc0186846584eabba684ec18a1c3a74d Mon Sep 17 00:00:00 2001 From: Stas Dmytryshyn Date: Thu, 28 Nov 2024 22:15:13 +0100 Subject: [PATCH] feat: add data integrity verifeir (#1808) --- cmd/vc-rest/startcmd/start.go | 34 +++++++++--- pkg/restapi/v1/refresh/controller.go | 26 ++++++--- pkg/restapi/v1/verifier/controller.go | 53 ++++++++++--------- .../verifypresentation_service.go | 27 +++++++--- 4 files changed, 91 insertions(+), 49 deletions(-) diff --git a/cmd/vc-rest/startcmd/start.go b/cmd/vc-rest/startcmd/start.go index 7394a2ab4..d6c777cbc 100644 --- a/cmd/vc-rest/startcmd/start.go +++ b/cmd/vc-rest/startcmd/start.go @@ -37,6 +37,9 @@ import ( "github.com/trustbloc/did-go/doc/ld/documentloader" "github.com/trustbloc/logutil-go/pkg/log" "github.com/trustbloc/logutil-go/pkg/otel/correlationidecho" + "github.com/trustbloc/vc-go/dataintegrity" + "github.com/trustbloc/vc-go/dataintegrity/suite/ecdsa2019" + "github.com/trustbloc/vc-go/dataintegrity/suite/eddsa2022" "github.com/trustbloc/vc-go/proof/defaults" "github.com/trustbloc/vc-go/vermethod" "go.mongodb.org/mongo-driver/mongo" @@ -834,6 +837,17 @@ func buildEchoHandler( TransactionStore: oidc4ciTransactionStore, }) + dataIntegrityVerifier, err := dataintegrity.NewVerifier(&dataintegrity.Options{ + DIDResolver: conf.VDR, + }, eddsa2022.NewVerifierInitializer(&eddsa2022.VerifierInitializerOptions{ + LDDocumentLoader: documentLoader, + }), ecdsa2019.NewVerifierInitializer(&ecdsa2019.VerifierInitializerOptions{ + LDDocumentLoader: documentLoader, + })) + if err != nil { + return nil, fmt.Errorf("new verifier: %w", err) + } + jweEncrypterCreator := func(jwk jose.JSONWebKey, alg jose.KeyAlgorithm, enc jose.ContentEncryption) (jose.Encrypter, error) { //nolint:lll return jose.NewEncrypter( enc, @@ -848,9 +862,10 @@ func buildEchoHandler( var verifyPresentationSvc verifypresentation.ServiceInterface verifyPresentationSvc = verifypresentation.New(&verifypresentation.Config{ - VcVerifier: verifyCredentialSvc, - DocumentLoader: documentLoader, - VDR: conf.VDR, + VcVerifier: verifyCredentialSvc, + DocumentLoader: documentLoader, + VDR: conf.VDR, + DataIntegrityVerifier: dataIntegrityVerifier, }) if conf.IsTraceEnabled { @@ -891,11 +906,12 @@ func buildEchoHandler( })) refresh.RegisterHandlers(e, refresh.NewController(&refresh.Config{ - RefreshService: refreshService, - ProfileService: issuerProfileSvc, - ProofChecker: proofChecker, - DocumentLoader: documentLoader, - IssuerVCSPublicHost: conf.StartupParameters.apiGatewayURL, + RefreshService: refreshService, + ProfileService: issuerProfileSvc, + ProofChecker: proofChecker, + DocumentLoader: documentLoader, + IssuerVCSPublicHost: conf.StartupParameters.apiGatewayURL, + DataIntegrityVerifier: dataIntegrityVerifier, })) issuerv1.RegisterHandlers(e, issuerv1.NewController(&issuerv1.Config{ @@ -1013,6 +1029,8 @@ func buildEchoHandler( Tracer: conf.Tracer, EventSvc: eventSvc, EventTopic: conf.StartupParameters.verifierEventTopic, + ProofChecker: proofChecker, + DataIntegrityVerifier: dataIntegrityVerifier, }) verifierv1.RegisterHandlers(e, verifierController) diff --git a/pkg/restapi/v1/refresh/controller.go b/pkg/restapi/v1/refresh/controller.go index 5e6806ba8..ceea6241e 100644 --- a/pkg/restapi/v1/refresh/controller.go +++ b/pkg/restapi/v1/refresh/controller.go @@ -14,6 +14,7 @@ import ( "github.com/labstack/echo/v4" "github.com/piprate/json-gold/ld" + "github.com/trustbloc/vc-go/dataintegrity" "github.com/trustbloc/vc-go/verifiable" "github.com/trustbloc/vcs/internal/utils" @@ -23,11 +24,12 @@ import ( var _ ServerInterface = (*Controller)(nil) // make sure Controller implements ServerInterface type Config struct { - RefreshService CredentialRefreshService - ProfileService ProfileService - ProofChecker ProofChecker - DocumentLoader ld.DocumentLoader - IssuerVCSPublicHost string + RefreshService CredentialRefreshService + ProfileService ProfileService + ProofChecker ProofChecker + DocumentLoader ld.DocumentLoader + IssuerVCSPublicHost string + DataIntegrityVerifier *dataintegrity.Verifier } type Controller struct { cfg *Config @@ -51,9 +53,19 @@ func (c *Controller) GetRefreshedCredential( return resterr.NewValidationError(resterr.InvalidValue, "request", err) } - pres, err := verifiable.ParsePresentation(req.VerifiablePresentation, + opts := []verifiable.PresentationOpt{ verifiable.WithPresJSONLDDocumentLoader(c.cfg.DocumentLoader), - verifiable.WithPresProofChecker(c.cfg.ProofChecker)) + verifiable.WithPresProofChecker(c.cfg.ProofChecker), + } + + if c.cfg.DataIntegrityVerifier != nil { + opts = append(opts, verifiable.WithPresDataIntegrityVerifier(c.cfg.DataIntegrityVerifier)) + } + + pres, err := verifiable.ParsePresentation( + req.VerifiablePresentation, + opts..., + ) if err != nil { return resterr.NewValidationError(resterr.InvalidValue, "verifiable_presentation", err) } diff --git a/pkg/restapi/v1/verifier/controller.go b/pkg/restapi/v1/verifier/controller.go index 3f17ff7ac..4f08f8ecd 100644 --- a/pkg/restapi/v1/verifier/controller.go +++ b/pkg/restapi/v1/verifier/controller.go @@ -27,8 +27,6 @@ import ( vdrapi "github.com/trustbloc/did-go/vdr/api" "github.com/trustbloc/logutil-go/pkg/log" "github.com/trustbloc/vc-go/dataintegrity" - "github.com/trustbloc/vc-go/dataintegrity/suite/ecdsa2019" - "github.com/trustbloc/vc-go/dataintegrity/suite/eddsa2022" "github.com/trustbloc/vc-go/jwt" "github.com/trustbloc/vc-go/presexch" "github.com/trustbloc/vc-go/proof/defaults" @@ -138,6 +136,7 @@ type Config struct { Tracer trace.Tracer EventSvc eventService EventTopic string + DataIntegrityVerifier *dataintegrity.Verifier } type metricsProvider interface { @@ -158,6 +157,7 @@ type Controller struct { eventSvc eventService eventTopic string vdr vdrapi.Registry + dataIntegrityVerifier *dataintegrity.Verifier } // NewController creates a new controller for Verifier Profile Management API. @@ -185,6 +185,7 @@ func NewController(config *Config) *Controller { eventSvc: config.EventSvc, eventTopic: config.EventTopic, vdr: config.VDR, + dataIntegrityVerifier: config.DataIntegrityVerifier, } } @@ -322,19 +323,16 @@ func (c *Controller) verifyPresentation( return nil, err } - dataVerifier, err := c.getDataIntegrityVerifier() - if err != nil { - return nil, resterr.NewSystemError(resterr.VerifierPresentationVerifierComponent, - "VerifyPresentation", err) - } - opts := []verifiable.PresentationOpt{ verifiable.WithPresProofChecker(c.proofChecker), verifiable.WithPresJSONLDDocumentLoader(c.documentLoader), - verifiable.WithPresDataIntegrityVerifier(dataVerifier), verifiable.WithPresHolderCheck(true), } + if c.dataIntegrityVerifier != nil { + opts = append(opts, verifiable.WithPresDataIntegrityVerifier(c.dataIntegrityVerifier)) + } + if body.Options != nil { opts = append(opts, verifiable.WithPresExpectedDataIntegrityFields( "authentication", @@ -369,21 +367,6 @@ func (c *Controller) verifyPresentation( return mapVerifyPresentationChecks(verRes, presentation), nil } -func (c *Controller) getDataIntegrityVerifier() (*dataintegrity.Verifier, error) { - verifier, err := dataintegrity.NewVerifier(&dataintegrity.Options{ - DIDResolver: c.vdr, - }, eddsa2022.NewVerifierInitializer(&eddsa2022.VerifierInitializerOptions{ - LDDocumentLoader: c.documentLoader, - }), ecdsa2019.NewVerifierInitializer(&ecdsa2019.VerifierInitializerOptions{ - LDDocumentLoader: c.documentLoader, - })) - if err != nil { - return nil, fmt.Errorf("new verifier: %w", err) - } - - return verifier, nil -} - // InitiateOidcInteraction initiates OpenID presentation flow through VCS. // POST /verifier/profiles/{profileID}/{profileVersion}/interactions/initiate-oidc. func (c *Controller) InitiateOidcInteraction(e echo.Context, profileID, profileVersion string) error { @@ -847,9 +830,18 @@ func (c *Controller) validateVPTokenJWT(vpToken string) (*VPTokenClaims, error) fmt.Errorf("token expired")) } - presentation, err := verifiable.ParsePresentation([]byte(vpToken), + opts := []verifiable.PresentationOpt{ verifiable.WithPresJSONLDDocumentLoader(c.documentLoader), verifiable.WithPresProofChecker(c.proofChecker), + } + + if c.dataIntegrityVerifier != nil { + opts = append(opts, verifiable.WithPresDataIntegrityVerifier(c.dataIntegrityVerifier)) + } + + presentation, err := verifiable.ParsePresentation( + []byte(vpToken), + opts..., ) if err != nil { return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token.vp", err) @@ -893,9 +885,18 @@ func (c *Controller) validateVPTokenCWT( } func (c *Controller) validateVPToken(vpToken string) (*VPTokenClaims, error) { - presentation, err := verifiable.ParsePresentation([]byte(vpToken), + opts := []verifiable.PresentationOpt{ verifiable.WithPresJSONLDDocumentLoader(c.documentLoader), verifiable.WithPresProofChecker(c.proofChecker), + } + + if c.dataIntegrityVerifier != nil { + opts = append(opts, verifiable.WithPresDataIntegrityVerifier(c.dataIntegrityVerifier)) + } + + presentation, err := verifiable.ParsePresentation( + []byte(vpToken), + opts..., ) if err != nil { return nil, resterr.NewValidationError(resterr.InvalidValue, "vp_token.vp", err) diff --git a/pkg/service/verifypresentation/verifypresentation_service.go b/pkg/service/verifypresentation/verifypresentation_service.go index 60d33f673..41a466761 100644 --- a/pkg/service/verifypresentation/verifypresentation_service.go +++ b/pkg/service/verifypresentation/verifypresentation_service.go @@ -19,6 +19,7 @@ import ( "github.com/trustbloc/did-go/doc/ld/validator" vdrapi "github.com/trustbloc/did-go/vdr/api" "github.com/trustbloc/logutil-go/pkg/log" + "github.com/trustbloc/vc-go/dataintegrity" "github.com/trustbloc/vc-go/proof/defaults" "github.com/trustbloc/vc-go/verifiable" "github.com/trustbloc/vc-go/vermethod" @@ -36,15 +37,17 @@ type vcVerifier interface { } type Config struct { - VDR vdrapi.Registry - DocumentLoader ld.DocumentLoader - VcVerifier vcVerifier + VDR vdrapi.Registry + DocumentLoader ld.DocumentLoader + VcVerifier vcVerifier + DataIntegrityVerifier *dataintegrity.Verifier } type Service struct { - vdr vdrapi.Registry - documentLoader ld.DocumentLoader - vcVerifier vcVerifier + vdr vdrapi.Registry + documentLoader ld.DocumentLoader + vcVerifier vcVerifier + dataIntegrityVerifier *dataintegrity.Verifier } func New(config *Config) *Service { @@ -300,12 +303,20 @@ func (s *Service) validatePresentationProof(targetPresentation interface{}, opts case *verifiable.Presentation: final = pres case []byte: - vp, err := verifiable.ParsePresentation( - pres, + presOpts := []verifiable.PresentationOpt{ verifiable.WithPresProofChecker( defaults.NewDefaultProofChecker(vermethod.NewVDRResolver(s.vdr)), ), verifiable.WithPresJSONLDDocumentLoader(s.documentLoader), + } + + if s.dataIntegrityVerifier != nil { + presOpts = append(presOpts, verifiable.WithPresDataIntegrityVerifier(s.dataIntegrityVerifier)) + } + + vp, err := verifiable.ParsePresentation( + pres, + presOpts..., ) if err != nil { return fmt.Errorf("verifiable presentation proof validation error : %w", err)