diff --git a/pkg/doc/jwt/verifier.go b/pkg/doc/jwt/verifier.go index d8897f358..8aee9dc4d 100644 --- a/pkg/doc/jwt/verifier.go +++ b/pkg/doc/jwt/verifier.go @@ -56,16 +56,25 @@ type BasicVerifier struct { func NewVerifier(resolver KeyResolver) *BasicVerifier { // TODO Support pluggable JWS verifiers // (https://github.com/hyperledger/aries-framework-go/issues/1267) - compositeVerifier := jose.NewCompositeAlgSigVerifier( - jose.AlgSignatureVerifier{ - Alg: signatureEdDSA, - Verifier: getVerifier(resolver, VerifyEdDSA), - }, - jose.AlgSignatureVerifier{ - Alg: signatureRS256, - Verifier: getVerifier(resolver, VerifyRS256), - }, - ) + verifiers := []verifier.SignatureVerifier{ + verifier.NewECDSAES256SignatureVerifier(), + verifier.NewECDSAES384SignatureVerifier(), + verifier.NewECDSAES521SignatureVerifier(), + verifier.NewEd25519SignatureVerifier(), + verifier.NewECDSASecp256k1SignatureVerifier(), + verifier.NewRSAPS256SignatureVerifier(), + verifier.NewRSARS256SignatureVerifier(), + } + + algVerifiers := make([]jose.AlgSignatureVerifier, 0, len(verifiers)) + for _, v := range verifiers { + algVerifiers = append(algVerifiers, jose.AlgSignatureVerifier{ + Alg: v.Algorithm(), + Verifier: getVerifier(resolver, v.Verify), + }) + } + + compositeVerifier := jose.NewCompositeAlgSigVerifier(algVerifiers[0], algVerifiers[1:]...) // TODO ECDSA to support NIST P256 curve // https://github.com/hyperledger/aries-framework-go/issues/1266 diff --git a/scripts/check_go_integration.sh b/scripts/check_go_integration.sh index a8eac1c15..406fd47a3 100755 --- a/scripts/check_go_integration.sh +++ b/scripts/check_go_integration.sh @@ -10,7 +10,7 @@ echo "Running aries-framework-go integration tests..." PWD=`pwd` cd test/bdd go test -count=1 -v -cover . -p 1 -timeout=45m -race -go test -count=1 -v -cover . -p 1 -timeout=30m -race -run presentproof,present_proof_controller,issue_credential,issue_credential_controller,webkms,waci_issuance,verifiable +go test -count=1 -v -cover . -p 1 -timeout=30m -race -run presentproof,present_proof_controller,issue_credential,issue_credential_controller,webkms,waci_issuance,verifiable,verifiable_jwt go test -count=1 -v -cover . -p 1 -timeout=30m -race -run didcomm_remote_crypto,outofbandv2 go test -count=1 -v -cover . -p 1 -timeout=45m -race -run outofband DEFAULT_KEY_TYPE="ecdsap256ieee1363" DEFAULT_KEY_AGREEMENT_TYPE="p256kw" go test -count=1 -v -cover . -p 1 -timeout=10m -race -run didcommv2 diff --git a/test/bdd/bddtests_test.go b/test/bdd/bddtests_test.go index f86107dc4..07f2f469d 100644 --- a/test/bdd/bddtests_test.go +++ b/test/bdd/bddtests_test.go @@ -26,6 +26,7 @@ import ( "github.com/hyperledger/aries-framework-go/test/bdd/pkg/didresolver" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/introduce" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/issuecredential" + "github.com/hyperledger/aries-framework-go/test/bdd/pkg/jwt" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/ld" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/mediator" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/messaging" @@ -210,6 +211,7 @@ func features() []feature { rfc0593.NewRestSDKSteps(), ld.NewLDControllerSteps(), ld.NewSDKSteps(), + jwt.NewJWTSDKSteps(), connection.NewSDKSteps(), connection.NewControllerSteps(), webkms.NewCryptoSDKSteps(), diff --git a/test/bdd/features/jwt.feature b/test/bdd/features/jwt.feature new file mode 100644 index 000000000..a39e6bfd4 --- /dev/null +++ b/test/bdd/features/jwt.feature @@ -0,0 +1,20 @@ +# +# Copyright SecureKey Technologies Inc. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +@verifiable_jwt +Feature: Issue and verify Verifiable Credential and Verifiable Presentation in JWS format + + Scenario Outline: Issue VC - verify VC - create VP - verify VP + Given crypto algorithm "<crypto>" + And "Berkley" issues VC at "2022-04-12" regarding "Master Degree" to "Alice" + Then "Alice" receives the VC and verifies it + Then "Alice" embeds the VC into VP + Then "Alice" verifies VP + Examples: + | crypto | + | "Ed25519" | + | "ECDSA Secp256r1" | + | "ECDSA Secp384r1" | \ No newline at end of file diff --git a/test/bdd/pkg/jwt/credential.go b/test/bdd/pkg/jwt/credential.go new file mode 100644 index 000000000..195790f14 --- /dev/null +++ b/test/bdd/pkg/jwt/credential.go @@ -0,0 +1,120 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package jwt + +import ( + "errors" + "time" + + "github.com/hyperledger/aries-framework-go/pkg/doc/util" + "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" + bddverifiable "github.com/hyperledger/aries-framework-go/test/bdd/pkg/verifiable" +) + +func (s *SDKSteps) issueCredential(issuer, issuedAt, subject, holder string) error { + err := s.createDID(issuer, holder) + if err != nil { + return err + } + + vcToIssue, err := s.createVC(issuedAt, subject, issuer) + if err != nil { + return err + } + + vcBytes, err := s.addVCProof(vcToIssue, issuer) + if err != nil { + return err + } + + s.issuedVCBytes = vcBytes + + return nil +} + +func (s *SDKSteps) verifyCredential(holder string) error { + vdr := s.bddContext.AgentCtx[holder].VDRegistry() + pKeyFetcher := verifiable.NewVDRKeyResolver(vdr).PublicKeyFetcher() + + loader, err := bddverifiable.CreateDocumentLoader() + if err != nil { + return err + } + + s.issuedVC, err = verifiable.ParseCredential(s.issuedVCBytes, + verifiable.WithPublicKeyFetcher(pKeyFetcher), + verifiable.WithJSONLDDocumentLoader(loader)) + if err != nil { + return err + } + + if s.issuedVC == nil { + return errors.New("received nil credential") + } + + return nil +} + +func (s *SDKSteps) createVC(issuedAt, subject, issuer string) (*verifiable.Credential, error) { + const dateLayout = "2006-01-02" + + issued, err := time.Parse(dateLayout, issuedAt) + if err != nil { + return nil, err + } + + vcToIssue := &verifiable.Credential{ + Context: []string{ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1", + }, + ID: "http://example.edu/credentials/1872", + Types: []string{ + "VerifiableCredential", + "UniversityDegreeCredential", + }, + Subject: subject, + Issuer: verifiable.Issuer{ + ID: s.getPublicDID(issuer).ID, + CustomFields: verifiable.CustomFields{"name": issuer}, + }, + Issued: util.NewTime(issued), + } + + return vcToIssue, nil +} + +func (s *SDKSteps) addVCProof(vc *verifiable.Credential, issuer string) ([]byte, error) { + doc := s.getPublicDID(issuer) + pubKeyID := doc.VerificationMethod[0].ID + + jwtClaims, err := vc.JWTClaims(false) + if err != nil { + return nil, err + } + + publicKeyJWK := s.bddContext.PublicKeys[issuer] + + keyType, err := publicKeyJWK.KeyType() + if err != nil { + return nil, err + } + + jwsAlgo, err := verifiable.KeyTypeToJWSAlgo(keyType) + if err != nil { + return nil, err + } + + signer := s.getSigner(issuer) + + jws, err := jwtClaims.MarshalJWS(jwsAlgo, signer, pubKeyID) + if err != nil { + return nil, err + } + + return []byte(jws), nil +} diff --git a/test/bdd/pkg/jwt/did.go b/test/bdd/pkg/jwt/did.go new file mode 100644 index 000000000..3ba74b6f9 --- /dev/null +++ b/test/bdd/pkg/jwt/did.go @@ -0,0 +1,49 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package jwt + +import ( + "github.com/hyperledger/aries-framework-go/pkg/doc/did" + bddagent "github.com/hyperledger/aries-framework-go/test/bdd/agent" + bddDIDExchange "github.com/hyperledger/aries-framework-go/test/bdd/pkg/didexchange" + "github.com/hyperledger/aries-framework-go/test/bdd/pkg/didresolver" +) + +func (s *SDKSteps) createDID(issuer, holder string) error { + const ( + inboundHost = "localhost" + inboundPort = "random" + endpointURL = "${SIDETREE_URL}" + acceptDidMethod = "sidetree" + ) + + participants := issuer + "," + holder + agentSDK := bddagent.NewSDKSteps() + agentSDK.SetContext(s.bddContext) + + err := agentSDK.CreateAgentWithHTTPDIDResolver(participants, inboundHost, inboundPort, endpointURL, acceptDidMethod) + if err != nil { + return err + } + + if err := s.createKeys(participants); err != nil { + return err + } + + if err := didresolver.CreateDIDDocument(s.bddContext, participants, "JsonWebKey2020"); err != nil { + return err + } + + didExchangeSDK := bddDIDExchange.NewDIDExchangeSDKSteps() + didExchangeSDK.SetContext(s.bddContext) + + return didExchangeSDK.WaitForPublicDID(participants, 10) +} + +func (s *SDKSteps) getPublicDID(agentName string) *did.Doc { + return s.bddContext.PublicDIDDocs[agentName] +} diff --git a/test/bdd/pkg/jwt/jwt_steps.go b/test/bdd/pkg/jwt/jwt_steps.go new file mode 100644 index 000000000..942e8be5a --- /dev/null +++ b/test/bdd/pkg/jwt/jwt_steps.go @@ -0,0 +1,150 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package jwt + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/x509" + _ "embed" //nolint:gci // required for go:embed + "errors" + "fmt" + "strings" + + "github.com/cucumber/godog" + + "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" + "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk/jwksupport" + "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" + "github.com/hyperledger/aries-framework-go/pkg/kms" + "github.com/hyperledger/aries-framework-go/pkg/kms/localkms" + "github.com/hyperledger/aries-framework-go/test/bdd/pkg/context" +) + +// SDKSteps is steps for VC and VP in JWT format using client SDK. +type SDKSteps struct { + crypto string + bddContext *context.BDDContext + issuedVCBytes []byte + issuedVC *verifiable.Credential + issuedVPBytes []byte +} + +// NewJWTSDKSteps creates steps for VC and VP in JWT format with SDK. +func NewJWTSDKSteps() *SDKSteps { + return &SDKSteps{} +} + +const ( + ed25519Crypto = "Ed25519" + secp256r1Crypto = "ECDSA Secp256r1" + secp384r1Crypto = "ECDSA Secp384r1" +) + +// SetContext is called before every scenario is run with a fresh new context. +func (s *SDKSteps) SetContext(ctx *context.BDDContext) { + s.bddContext = ctx +} + +// RegisterSteps registers steps for VC and VP in JWT format. +func (s *SDKSteps) RegisterSteps(gs *godog.Suite) { + gs.Step(`^crypto algorithm ""([^"]*)""$`, s.setCryptoAlgorithm) + gs.Step(`^"([^"]*)" issues VC at "([^"]*)" regarding "([^"]*)" to "([^"]*)"$`, s.issueCredential) + gs.Step(`^"([^"]*)" receives the VC and verifies it$`, s.verifyCredential) + gs.Step(`^"([^"]*)" embeds the VC into VP$`, s.createPresentation) + gs.Step(`^"([^"]*)" verifies VP$`, s.verifyPresentation) +} + +func (s *SDKSteps) getSigner(agent string) verifiable.Signer { + cr := s.bddContext.AgentCtx[agent].Crypto() + return newCryptoSigner(cr, s.bddContext.KeyHandles[agent]) +} + +func (s *SDKSteps) createKeys(participants string) error { + for _, agent := range strings.Split(participants, ",") { + if err := s.createKeyPair(agent, s.crypto); err != nil { + return err + } + } + + return nil +} + +func (s *SDKSteps) createKeyPair(agent, crypto string) error { + localKMS, ok := s.bddContext.AgentCtx[agent].KMS().(*localkms.LocalKMS) + if !ok { + return errors.New("expected LocalKMS type of KMS") + } + + keyType := mapCryptoKeyType(crypto) + + kid, kh, err := localKMS.Create(keyType) + if err != nil { + return err + } + + pubKeyBytes, _, err := localKMS.ExportPubKeyBytes(kid) + if err != nil { + return err + } + + pubKeyJWK, err := createJWK(pubKeyBytes, keyType) + if err != nil { + return err + } + + s.bddContext.PublicKeys[agent] = pubKeyJWK + s.bddContext.KeyHandles[agent] = kh + + return nil +} + +func (s *SDKSteps) setCryptoAlgorithm(crypto string) error { + s.crypto = crypto + + return nil +} + +func createJWK(pubKeyBytes []byte, keyType kms.KeyType) (*jwk.JWK, error) { + var pubKey interface{} + + switch keyType { + case kms.ECDSAP256TypeDER, kms.ECDSAP384TypeDER: + pk, err := x509.ParsePKIXPublicKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("parse ECDSA public key: %w", err) + } + + ecdsaPubKey, ok := pk.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("unexpected type of ecdsa public key") + } + + pubKey = ecdsaPubKey + + case kms.ED25519Type: + pubKey = ed25519.PublicKey(pubKeyBytes) + + default: + return nil, errors.New("unsupported key type: " + string(keyType)) + } + + return jwksupport.JWKFromKey(pubKey) +} + +func mapCryptoKeyType(crypto string) kms.KeyType { + switch crypto { + case ed25519Crypto: + return kms.ED25519Type + case secp256r1Crypto: + return kms.ECDSAP256TypeDER + case secp384r1Crypto: + return kms.ECDSAP384TypeDER + default: + panic("unsupported crypto type: " + crypto) + } +} diff --git a/test/bdd/pkg/jwt/presentation.go b/test/bdd/pkg/jwt/presentation.go new file mode 100644 index 000000000..d1734a6c7 --- /dev/null +++ b/test/bdd/pkg/jwt/presentation.go @@ -0,0 +1,78 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package jwt + +import ( + "errors" + "fmt" + + "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" + bddverifiable "github.com/hyperledger/aries-framework-go/test/bdd/pkg/verifiable" +) + +func (s *SDKSteps) createPresentation(holder string) error { + doc := s.getPublicDID(holder) + pubKeyID := doc.VerificationMethod[0].ID + + publicKeyJWK := s.bddContext.PublicKeys[holder] + + keyType, err := publicKeyJWK.KeyType() + if err != nil { + return err + } + + jwsAlgo, err := verifiable.KeyTypeToJWSAlgo(keyType) + if err != nil { + return err + } + + signer := s.getSigner(holder) + + vp, err := verifiable.NewPresentation(verifiable.WithCredentials(s.issuedVC)) + if err != nil { + return fmt.Errorf("failed to build VP from VC: %w", err) + } + + vp.Holder = doc.ID + + jwtClaims, err := vp.JWTClaims([]string{}, false) + if err != nil { + return fmt.Errorf("failed to create JWT claims of VP: %w", err) + } + + jws, err := jwtClaims.MarshalJWS(jwsAlgo, signer, pubKeyID) + if err != nil { + return err + } + + s.issuedVPBytes = []byte(jws) + + return nil +} + +func (s *SDKSteps) verifyPresentation(holder string) error { + vdr := s.bddContext.AgentCtx[holder].VDRegistry() + pKeyFetcher := verifiable.NewVDRKeyResolver(vdr).PublicKeyFetcher() + + loader, err := bddverifiable.CreateDocumentLoader() + if err != nil { + return err + } + + vp, err := verifiable.ParsePresentation(s.issuedVPBytes, + verifiable.WithPresPublicKeyFetcher(pKeyFetcher), + verifiable.WithPresJSONLDDocumentLoader(loader)) + if err != nil { + return err + } + + if vp == nil { + return errors.New("received nil presentation") + } + + return nil +} diff --git a/test/bdd/pkg/jwt/signer.go b/test/bdd/pkg/jwt/signer.go new file mode 100644 index 000000000..176bf450c --- /dev/null +++ b/test/bdd/pkg/jwt/signer.go @@ -0,0 +1,28 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package jwt + +import ( + ariescrypto "github.com/hyperledger/aries-framework-go/pkg/crypto" +) + +type cryptoSigner struct { + cr ariescrypto.Crypto + kh interface{} +} + +func newCryptoSigner(cr ariescrypto.Crypto, keyHandle interface{}) *cryptoSigner { + return &cryptoSigner{cr: cr, kh: keyHandle} +} + +func (s *cryptoSigner) Sign(data []byte) ([]byte, error) { + return s.cr.Sign(data, s.kh) +} + +func (s *cryptoSigner) Alg() string { + return "" +} diff --git a/test/bdd/pkg/waci/common.go b/test/bdd/pkg/waci/common.go index 1b7f40427..45d4396a4 100644 --- a/test/bdd/pkg/waci/common.go +++ b/test/bdd/pkg/waci/common.go @@ -14,16 +14,13 @@ import ( "github.com/google/uuid" - "github.com/hyperledger/aries-framework-go/component/storageutil/mem" issuecredentialclient "github.com/hyperledger/aries-framework-go/pkg/client/issuecredential" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" "github.com/hyperledger/aries-framework-go/pkg/doc/cm" - "github.com/hyperledger/aries-framework-go/pkg/doc/ld" "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" - ldstore "github.com/hyperledger/aries-framework-go/pkg/store/ld" - bddldcontext "github.com/hyperledger/aries-framework-go/test/bdd/pkg/ldcontext" + bddverifiable "github.com/hyperledger/aries-framework-go/test/bdd/pkg/verifiable" ) const expectedVCID = "https://eu.com/claims/DriversLicense" @@ -212,7 +209,7 @@ func generateCredentialFulfillmentAttachmentWithoutProof() (*decorator.GenericAt "CredentialFulfillment", } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return nil, err } @@ -285,7 +282,7 @@ func generateCredentialApplicationAttachment(credentialManifest *cm.CredentialMa return nil, err } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return nil, err } @@ -349,7 +346,7 @@ func generateIssueCredentialMsg(msgType string) (*issuecredentialclient.IssueCre return nil, err } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return nil, err } @@ -485,7 +482,7 @@ func getVCFromCredentialFulfillmentAttachment(credentialFulfillmentAttachment *d return verifiable.Credential{}, err } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return verifiable.Credential{}, err } @@ -502,40 +499,3 @@ func getVCFromCredentialFulfillmentAttachment(credentialFulfillmentAttachment *d return vcs[0], nil } - -type docLoaderProvider struct { - ContextStore ldstore.ContextStore - RemoteProviderStore ldstore.RemoteProviderStore -} - -func (p *docLoaderProvider) JSONLDContextStore() ldstore.ContextStore { - return p.ContextStore -} - -func (p *docLoaderProvider) JSONLDRemoteProviderStore() ldstore.RemoteProviderStore { - return p.RemoteProviderStore -} - -func createDocumentLoader() (*ld.DocumentLoader, error) { - contextStore, err := ldstore.NewContextStore(mem.NewProvider()) - if err != nil { - return nil, err - } - - remoteProviderStore, err := ldstore.NewRemoteProviderStore(mem.NewProvider()) - if err != nil { - return nil, err - } - - p := &docLoaderProvider{ - ContextStore: contextStore, - RemoteProviderStore: remoteProviderStore, - } - - loader, err := ld.NewDocumentLoader(p, ld.WithExtraContexts(bddldcontext.Extra()...)) - if err != nil { - return nil, err - } - - return loader, nil -} diff --git a/test/bdd/pkg/waci/waci_issuance_didcomm_v1_sdk_steps.go b/test/bdd/pkg/waci/waci_issuance_didcomm_v1_sdk_steps.go index 0f678e85d..034a126d8 100644 --- a/test/bdd/pkg/waci/waci_issuance_didcomm_v1_sdk_steps.go +++ b/test/bdd/pkg/waci/waci_issuance_didcomm_v1_sdk_steps.go @@ -29,6 +29,7 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/context" bddDIDExchange "github.com/hyperledger/aries-framework-go/test/bdd/pkg/didexchange" + bddverifiable "github.com/hyperledger/aries-framework-go/test/bdd/pkg/verifiable" ) var ( @@ -256,7 +257,7 @@ func (i *IssuanceSDKDIDCommV1Steps) acceptCredentialApplication(issuerName strin return fmt.Errorf("failed to marshal credential_application object: %w", err) } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return err } @@ -372,7 +373,7 @@ func (i *IssuanceSDKDIDCommV1Steps) checkAttachments(attachmentsFromOfferMsg []d expectedCredentialManifestID, credentialFulfillment.ManifestID) } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return err } diff --git a/test/bdd/pkg/waci/waci_issuance_didcomm_v2_sdk_steps.go b/test/bdd/pkg/waci/waci_issuance_didcomm_v2_sdk_steps.go index 29fbb5197..f6530c086 100644 --- a/test/bdd/pkg/waci/waci_issuance_didcomm_v2_sdk_steps.go +++ b/test/bdd/pkg/waci/waci_issuance_didcomm_v2_sdk_steps.go @@ -27,6 +27,7 @@ import ( "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" "github.com/hyperledger/aries-framework-go/test/bdd/pkg/context" + bddverifiable "github.com/hyperledger/aries-framework-go/test/bdd/pkg/verifiable" ) var ( @@ -244,7 +245,7 @@ func (i *IssuanceSDKDIDCommV2Steps) acceptCredentialApplication(issuerName strin return fmt.Errorf("failed to marshal credential_application object: %w", err) } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return err } @@ -424,7 +425,7 @@ func (i *IssuanceSDKDIDCommV2Steps) checkAttachments(attachmentsFromOfferMsg []d expectedCredentialManifestID, credentialFulfillment.ManifestID) } - documentLoader, err := createDocumentLoader() + documentLoader, err := bddverifiable.CreateDocumentLoader() if err != nil { return err }