github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/presexch/definition_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package presexch_test 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/sha256" 13 "encoding/json" 14 "fmt" 15 "io/ioutil" 16 "os" 17 "strings" 18 "testing" 19 "time" 20 21 "github.com/PaesslerAG/gval" 22 "github.com/PaesslerAG/jsonpath" 23 "github.com/google/uuid" 24 "github.com/stretchr/testify/require" 25 26 "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" 27 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto" 28 "github.com/hyperledger/aries-framework-go/pkg/doc/ld" 29 . "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" 30 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" 31 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite" 32 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignature2020" 33 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier" 34 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 35 "github.com/hyperledger/aries-framework-go/pkg/doc/util/signature" 36 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 37 "github.com/hyperledger/aries-framework-go/pkg/internal/ldtestutil" 38 "github.com/hyperledger/aries-framework-go/pkg/kms" 39 "github.com/hyperledger/aries-framework-go/pkg/kms/localkms" 40 mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" 41 "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 42 "github.com/hyperledger/aries-framework-go/pkg/secretlock/noop" 43 "github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint" 44 ) 45 46 const errMsgSchema = "credentials do not satisfy requirements" 47 48 // nolint: gochecknoglobals 49 var ( 50 strFilterType = "string" 51 arrFilterType = "array" 52 intFilterType = "integer" 53 54 subIsIssuerRequired = Required 55 ) 56 57 func TestPresentationDefinition_IsValid(t *testing.T) { 58 samples := []string{"sample_1.json", "sample_2.json", "sample_3.json"} 59 60 for _, sample := range samples { 61 file := sample 62 t.Run(file, func(t *testing.T) { 63 var pd *PresentationDefinition 64 parseJSONFile(t, "testdata/"+file, &pd) 65 66 require.NoError(t, pd.ValidateSchema()) 67 }) 68 } 69 70 t.Run("id is required", func(t *testing.T) { 71 errMsg := "presentation_definition: id is required,presentation_definition: input_descriptors is required" 72 pd := &PresentationDefinition{ 73 SubmissionRequirements: []*SubmissionRequirement{{Rule: All, From: "A"}}, 74 } 75 require.EqualError(t, pd.ValidateSchema(), errMsg) 76 }) 77 } 78 79 func TestPresentationDefinition_CreateVP(t *testing.T) { 80 lddl := createTestJSONLDDocumentLoader(t) 81 82 t.Run("Checks schema", func(t *testing.T) { 83 pd := &PresentationDefinition{ID: uuid.New().String()} 84 85 vp, err := pd.CreateVP(nil, nil) 86 87 require.EqualError(t, err, "presentation_definition: input_descriptors is required") 88 require.Nil(t, vp) 89 }) 90 91 t.Run("Checks submission requirements", func(t *testing.T) { 92 issuerID := "did:example:76e12ec712ebc6f1c221ebfeb1f" 93 94 vc1JWT := &verifiable.Credential{ 95 Issued: util.NewTime(time.Now()), 96 Context: []string{verifiable.ContextURI}, 97 Types: []string{verifiable.VCType}, 98 ID: "http://example.edu/credentials/1872", 99 Subject: []verifiable.Subject{{ID: issuerID}}, 100 Issuer: verifiable.Issuer{ID: issuerID}, 101 CustomFields: map[string]interface{}{ 102 "first_name": "Jesse", 103 "last_name": "Travis", 104 "age": 17, 105 }, 106 // vc as jwt does not use proof, do not set it here. 107 } 108 109 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 110 require.NoError(t, err) 111 112 vc1JWT.JWT = createEdDSAJWS(t, vc1JWT, ed25519Signer, "76e12ec712ebc6f1c221ebfeb1f", true) 113 114 candidateVCs := []*verifiable.Credential{ 115 vc1JWT, 116 { 117 Context: []string{verifiable.ContextURI}, 118 Types: []string{verifiable.VCType}, 119 ID: "http://example.edu/credentials/1872", 120 CustomFields: map[string]interface{}{ 121 "first_name": "Jesse", 122 }, 123 Proofs: []verifiable.Proof{{"type": "JsonWebSignature2020"}}, 124 }, 125 { 126 Context: []string{verifiable.ContextURI}, 127 Types: []string{verifiable.VCType}, 128 ID: "http://example.edu/credentials/1872", 129 Subject: []verifiable.Subject{{ID: issuerID}}, 130 Issuer: verifiable.Issuer{ID: issuerID}, 131 CustomFields: map[string]interface{}{ 132 "first_name": "Jesse", 133 "last_name": "Travis", 134 "age": 17, 135 }, 136 Proofs: []verifiable.Proof{{"type": "JsonWebSignature2020"}}, 137 }, 138 { 139 Context: []string{verifiable.ContextURI}, 140 Types: []string{verifiable.VCType}, 141 ID: "http://example.edu/credentials/1872", 142 Subject: []verifiable.Subject{{ID: issuerID}}, 143 Issuer: verifiable.Issuer{ID: issuerID}, 144 CustomFields: map[string]interface{}{ 145 "first_name": "Jesse", 146 "last_name": "Travis", 147 "age": 2, 148 }, 149 Proofs: []verifiable.Proof{{"type": "JsonWebSignature2020"}}, 150 }, 151 } 152 153 tests := []struct { 154 name string 155 format string 156 vFormat *Format 157 }{ 158 /*{ 159 name: "test LDP format", 160 format: FormatLDP, 161 vFormat: &Format{ 162 Ldp: &LdpType{ProofType: []string{"JsonWebSignature2020"}}, 163 }, 164 }, 165 { 166 name: "test LDPVP format", 167 format: FormatLDPVP, 168 vFormat: &Format{ 169 LdpVP: &LdpType{ProofType: []string{"JsonWebSignature2020"}}, 170 }, 171 }, 172 { 173 name: "test LDPVC format", 174 format: FormatLDPVC, 175 vFormat: &Format{ 176 LdpVC: &LdpType{ProofType: []string{"JsonWebSignature2020"}}, 177 }, 178 }, 179 { 180 name: "test JWT format", 181 format: FormatJWT, 182 vFormat: &Format{ 183 Jwt: &JwtType{Alg: []string{"EdDSA"}}, 184 }, 185 }, 186 { 187 name: "test JWTVC format", 188 format: FormatJWTVC, 189 vFormat: &Format{ 190 JwtVC: &JwtType{Alg: []string{"EdDSA"}}, 191 }, 192 },*/ 193 { 194 name: "test JWTVP format", 195 format: FormatJWTVP, 196 vFormat: &Format{ 197 JwtVP: &JwtType{Alg: []string{"EdDSA"}}, 198 }, 199 }, 200 } 201 202 for _, tc := range tests { 203 t.Run(tc.name, func(t *testing.T) { 204 pd := &PresentationDefinition{ 205 ID: uuid.New().String(), 206 SubmissionRequirements: []*SubmissionRequirement{ 207 { 208 Rule: "all", 209 From: "A", 210 }, 211 { 212 Rule: "pick", 213 Count: 1, 214 FromNested: []*SubmissionRequirement{ 215 { 216 Rule: "all", 217 From: "teenager", 218 }, 219 { 220 Rule: "all", 221 From: "child", 222 }, 223 { 224 Rule: "pick", 225 From: "adult", 226 Min: 2, 227 }, 228 }, 229 }, 230 }, 231 InputDescriptors: []*InputDescriptor{{ 232 ID: uuid.New().String(), 233 Group: []string{"A"}, 234 Schema: []*Schema{{ 235 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 236 }}, 237 Constraints: &Constraints{ 238 SubjectIsIssuer: &subIsIssuerRequired, 239 Fields: []*Field{{ 240 Path: []string{"$.first_name", "$.last_name"}, 241 }}, 242 }, 243 }, { 244 ID: uuid.New().String(), 245 Group: []string{"child"}, 246 Schema: []*Schema{{ 247 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 248 }}, 249 Constraints: &Constraints{ 250 SubjectIsIssuer: &subIsIssuerRequired, 251 Fields: []*Field{{ 252 Path: []string{"$.age"}, 253 Filter: &Filter{ 254 Type: &intFilterType, 255 Minimum: 3, 256 Maximum: 12, 257 }, 258 }}, 259 }, 260 }, { 261 ID: uuid.New().String(), 262 Group: []string{"teenager"}, 263 Schema: []*Schema{{ 264 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 265 }}, 266 Constraints: &Constraints{ 267 SubjectIsIssuer: &subIsIssuerRequired, 268 Fields: []*Field{{ 269 Path: []string{"$.age"}, 270 Filter: &Filter{ 271 Type: &intFilterType, 272 Minimum: 13, 273 Maximum: 17, 274 }, 275 }}, 276 }, 277 }, { 278 ID: uuid.New().String(), 279 Group: []string{"adult"}, 280 Schema: []*Schema{{ 281 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 282 }}, 283 Constraints: &Constraints{ 284 SubjectIsIssuer: &subIsIssuerRequired, 285 Fields: []*Field{{ 286 Path: []string{"$.age"}, 287 Filter: &Filter{ 288 Type: &intFilterType, 289 Minimum: 18, 290 Maximum: 23, 291 }, 292 }}, 293 }, 294 }}, 295 Format: tc.vFormat, 296 } 297 298 vp, err := pd.CreateVP(candidateVCs, lddl) 299 300 require.NoError(t, err) 301 require.NotNil(t, vp) 302 require.Equal(t, 1, len(vp.Credentials())) 303 304 checkSubmission(t, vp, pd) 305 checkVP(t, vp) 306 }) 307 } 308 }) 309 310 t.Run("Checks submission requirements (no descriptor)", func(t *testing.T) { 311 issuerID := uuid.New().String() 312 313 pd := &PresentationDefinition{ 314 ID: uuid.New().String(), 315 SubmissionRequirements: []*SubmissionRequirement{ 316 { 317 Rule: "all", 318 From: "A", 319 }, 320 { 321 Rule: "pick", 322 Count: 1, 323 FromNested: []*SubmissionRequirement{ 324 { 325 Rule: "all", 326 From: "teenager", 327 }, 328 }, 329 }, 330 }, 331 InputDescriptors: []*InputDescriptor{{ 332 ID: uuid.New().String(), 333 Group: []string{"A"}, 334 Schema: []*Schema{{ 335 URI: verifiable.ContextURI, 336 }}, 337 Constraints: &Constraints{ 338 SubjectIsIssuer: &subIsIssuerRequired, 339 Fields: []*Field{{ 340 Path: []string{"$.first_name", "$.last_name"}, 341 }}, 342 }, 343 }}, 344 } 345 346 vp, err := pd.CreateVP([]*verifiable.Credential{ 347 { 348 Context: []string{verifiable.ContextURI}, 349 Types: []string{verifiable.VCType}, 350 ID: uuid.New().String(), 351 CustomFields: map[string]interface{}{ 352 "first_name": "Jesse", 353 }, 354 }, { 355 ID: uuid.New().String(), 356 Subject: []verifiable.Subject{{ID: issuerID}}, 357 Issuer: verifiable.Issuer{ID: issuerID}, 358 CustomFields: map[string]interface{}{ 359 "first_name": "Jesse", 360 "last_name": "Travis", 361 "age": 17, 362 }, 363 }, 364 }, lddl) 365 366 require.EqualError(t, err, "no descriptors for from: teenager") 367 require.Nil(t, vp) 368 }) 369 370 t.Run("Predicate", func(t *testing.T) { 371 predicate := Required 372 373 pd := &PresentationDefinition{ 374 ID: uuid.New().String(), 375 InputDescriptors: []*InputDescriptor{{ 376 ID: uuid.New().String(), 377 Schema: []*Schema{{ 378 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 379 }}, 380 Constraints: &Constraints{ 381 Fields: []*Field{{ 382 Path: []string{"$.first_name", "$.last_name"}, 383 Predicate: &predicate, 384 Filter: &Filter{Type: &strFilterType}, 385 }}, 386 }, 387 }}, 388 } 389 390 vp, err := pd.CreateVP([]*verifiable.Credential{ 391 { 392 Context: []string{verifiable.ContextURI}, 393 Types: []string{verifiable.VCType}, 394 ID: "http://example.edu/credentials/1872", 395 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 396 Issued: &util.TimeWrapper{ 397 Time: time.Now(), 398 }, 399 Issuer: verifiable.Issuer{ 400 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 401 }, 402 CustomFields: map[string]interface{}{ 403 "first_name": "First name", 404 "last_name": "Last name", 405 "info": "Info", 406 }, 407 }, 408 }, lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 409 410 require.NoError(t, err) 411 require.NotNil(t, vp) 412 require.Equal(t, 1, len(vp.Credentials())) 413 414 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 415 require.True(t, ok) 416 417 require.True(t, vc.CustomFields["first_name"].(bool)) 418 require.True(t, vc.CustomFields["last_name"].(bool)) 419 require.EqualValues(t, "Info", vc.CustomFields["info"]) 420 421 checkSubmission(t, vp, pd) 422 checkVP(t, vp) 423 }) 424 425 t.Run("Get By Credential Type", func(t *testing.T) { 426 const queryByCredType = `{ 427 "id": "69ddc987-55c2-4f1f-acea-f2838be10607", 428 "input_descriptors": [ 429 { 430 "id": "26b00531-caa1-49f3-a5a1-4a0eae8c0925", 431 "constraints": { 432 "fields": [ 433 { 434 "path": [ 435 "$.type", 436 "$.vc.type" 437 ], 438 "filter": { 439 "type": "array", 440 "contains": { 441 "type": "string", 442 "const": "DemoCred" 443 } 444 } 445 } 446 ] 447 } 448 } 449 ] 450 }` 451 452 var pd PresentationDefinition 453 require.NoError(t, json.Unmarshal([]byte(queryByCredType), &pd)) 454 455 vp, err := pd.CreateVP([]*verifiable.Credential{ 456 { 457 Context: []string{verifiable.ContextURI}, 458 Types: []string{verifiable.VCType, "DemoCred"}, 459 ID: "http://example.edu/credentials/1872", 460 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 461 Issued: &util.TimeWrapper{ 462 Time: time.Now(), 463 }, 464 Issuer: verifiable.Issuer{ 465 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 466 }, 467 CustomFields: map[string]interface{}{ 468 "first_name": "First name", 469 "last_name": "Last name", 470 "info": "Info", 471 }, 472 }, 473 }, lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 474 475 require.NoError(t, err) 476 require.NotNil(t, vp) 477 require.Equal(t, 1, len(vp.Credentials())) 478 479 checkSubmission(t, vp, &pd) 480 checkVP(t, vp) 481 }) 482 483 t.Run("Predicate (limit disclosure)", func(t *testing.T) { 484 required := Required 485 486 pd := &PresentationDefinition{ 487 ID: uuid.New().String(), 488 InputDescriptors: []*InputDescriptor{{ 489 ID: uuid.New().String(), 490 Schema: []*Schema{{ 491 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 492 }}, 493 Constraints: &Constraints{ 494 LimitDisclosure: &required, 495 Fields: []*Field{{ 496 Path: []string{"$.first_name", "$.last_name"}, 497 Predicate: &required, 498 Filter: &Filter{Type: &strFilterType}, 499 }}, 500 }, 501 }}, 502 } 503 504 vp, err := pd.CreateVP([]*verifiable.Credential{ 505 { 506 Context: []string{verifiable.ContextURI}, 507 Types: []string{verifiable.VCType}, 508 ID: "http://example.edu/credentials/1872", 509 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 510 Issued: &util.TimeWrapper{ 511 Time: time.Now(), 512 }, 513 Issuer: verifiable.Issuer{ 514 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 515 }, 516 CustomFields: map[string]interface{}{ 517 "first_name": "First name", 518 "last_name": "Last name", 519 "info": "Info", 520 }, 521 }, 522 }, lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 523 524 require.NoError(t, err) 525 require.NotNil(t, vp) 526 require.Equal(t, 1, len(vp.Credentials())) 527 528 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 529 require.True(t, ok) 530 531 require.True(t, vc.CustomFields["first_name"].(bool)) 532 require.True(t, vc.CustomFields["last_name"].(bool)) 533 534 _, ok = vc.CustomFields["info"] 535 require.False(t, ok) 536 537 checkSubmission(t, vp, pd) 538 checkVP(t, vp) 539 }) 540 541 t.Run("SD-JWT: Limit Disclosure + SD Claim paths", func(t *testing.T) { 542 required := Required 543 544 pd := &PresentationDefinition{ 545 ID: uuid.New().String(), 546 InputDescriptors: []*InputDescriptor{{ 547 ID: uuid.New().String(), 548 Schema: []*Schema{{ 549 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 550 }}, 551 Constraints: &Constraints{ 552 LimitDisclosure: &required, 553 Fields: []*Field{{ 554 Path: []string{ 555 "$.credentialSubject.family_name", 556 "$.credentialSubject.given_name", 557 "$.credentialSubject.address.country", 558 }, 559 }}, 560 }, 561 }}, 562 } 563 564 testVC := getTestVC() 565 566 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 567 require.NoError(t, err) 568 569 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 570 571 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 572 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 573 574 require.NoError(t, err) 575 require.NotNil(t, vp) 576 require.Equal(t, 1, len(vp.Credentials())) 577 578 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 579 require.True(t, ok) 580 581 require.Len(t, vc.SDJWTDisclosures, 3) 582 583 require.Len(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["_sd"].([]interface{}), 6) 584 require.NotNil(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["address"]) 585 586 _, ok = vc.Subject.([]verifiable.Subject)[0].CustomFields["email"] 587 require.False(t, ok) 588 589 displayVC, err := vc.CreateDisplayCredential(verifiable.DisplayAllDisclosures()) 590 require.NoError(t, err) 591 592 printObject(t, "Display VC - Limited", displayVC) 593 594 require.Equal(t, "John", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["given_name"]) 595 require.Equal(t, "Doe", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["family_name"]) 596 597 checkSubmission(t, vp, pd) 598 checkVP(t, vp) 599 }) 600 601 t.Run("SD-JWT: Limit Disclosure + SD Claim paths + additional filter", func(t *testing.T) { 602 required := Required 603 604 pd := &PresentationDefinition{ 605 ID: uuid.New().String(), 606 InputDescriptors: []*InputDescriptor{{ 607 ID: uuid.New().String(), 608 Schema: []*Schema{{ 609 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 610 }}, 611 Constraints: &Constraints{ 612 LimitDisclosure: &required, 613 Fields: []*Field{ 614 { 615 Path: []string{ 616 "$.credentialSubject.family_name", 617 "$.credentialSubject.given_name", 618 "$.credentialSubject.address.country", 619 }, 620 }, 621 { 622 Path: []string{ 623 "$.credentialSchema[0].id", 624 }, 625 Filter: &Filter{ 626 Type: &strFilterType, 627 Const: "https://www.w3.org/TR/vc-data-model/2.0/#types", 628 }, 629 }, 630 }, 631 }, 632 }}, 633 } 634 635 testVC := getTestVC() 636 637 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 638 require.NoError(t, err) 639 640 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 641 642 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 643 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 644 645 require.NoError(t, err) 646 require.NotNil(t, vp) 647 require.Equal(t, 1, len(vp.Credentials())) 648 649 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 650 require.True(t, ok) 651 652 require.Len(t, vc.SDJWTDisclosures, 3) 653 654 require.Len(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["_sd"].([]interface{}), 6) 655 require.NotNil(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["address"]) 656 657 _, ok = vc.Subject.([]verifiable.Subject)[0].CustomFields["email"] 658 require.False(t, ok) 659 660 displayVC, err := vc.CreateDisplayCredential(verifiable.DisplayAllDisclosures()) 661 require.NoError(t, err) 662 663 printObject(t, "Display VC", displayVC) 664 665 require.Equal(t, "John", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["given_name"]) 666 require.Equal(t, "Doe", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["family_name"]) 667 668 checkSubmission(t, vp, pd) 669 checkVP(t, vp) 670 }) 671 672 t.Run("SD-JWT: Limit Disclosure + non-SD claim path", func(t *testing.T) { 673 required := Required 674 675 pd := &PresentationDefinition{ 676 ID: uuid.New().String(), 677 InputDescriptors: []*InputDescriptor{{ 678 ID: uuid.New().String(), 679 Schema: []*Schema{{ 680 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 681 }}, 682 Constraints: &Constraints{ 683 LimitDisclosure: &required, 684 Fields: []*Field{{ 685 Path: []string{ 686 "$.id", 687 }, 688 }}, 689 }, 690 }}, 691 } 692 693 testVC := getTestVC() 694 695 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 696 require.NoError(t, err) 697 698 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 699 700 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 701 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 702 703 require.NoError(t, err) 704 require.NotNil(t, vp) 705 require.Equal(t, 1, len(vp.Credentials())) 706 707 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 708 require.True(t, ok) 709 710 // there is only one non-SD claim path is in the fields array - hence no selective disclosures 711 require.Len(t, vc.SDJWTDisclosures, 0) 712 713 require.Len(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["_sd"].([]interface{}), 6) 714 715 displayVC, err := vc.CreateDisplayCredential(verifiable.DisplayAllDisclosures()) 716 require.NoError(t, err) 717 718 printObject(t, "Display VC - No Selective Disclosures", displayVC) 719 720 require.Nil(t, displayVC.Subject.([]verifiable.Subject)[0].CustomFields["given_name"]) 721 require.Nil(t, displayVC.Subject.([]verifiable.Subject)[0].CustomFields["email"]) 722 723 checkSubmission(t, vp, pd) 724 checkVP(t, vp) 725 }) 726 727 t.Run("SD-JWT: No Limit Disclosure + Predicate Satisfied", func(t *testing.T) { 728 required := Required 729 730 pd := &PresentationDefinition{ 731 ID: uuid.New().String(), 732 InputDescriptors: []*InputDescriptor{{ 733 ID: uuid.New().String(), 734 Schema: []*Schema{{ 735 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 736 }}, 737 Constraints: &Constraints{ 738 Fields: []*Field{{ 739 Path: []string{ 740 "$.credentialSubject.family_name", 741 }, 742 Predicate: &required, 743 Filter: &Filter{Type: &strFilterType}, 744 }}, 745 }, 746 }}, 747 } 748 749 testVC := getTestVC() 750 751 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 752 require.NoError(t, err) 753 754 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 755 756 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 757 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 758 759 require.NoError(t, err) 760 require.NotNil(t, vp) 761 require.Equal(t, 1, len(vp.Credentials())) 762 763 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 764 require.True(t, ok) 765 766 require.Len(t, vc.SDJWTDisclosures, 10) 767 768 require.Len(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["_sd"].([]interface{}), 6) 769 require.NotNil(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["address"]) 770 771 _, ok = vc.Subject.([]verifiable.Subject)[0].CustomFields["email"] 772 require.False(t, ok) 773 774 displayVC, err := vc.CreateDisplayCredential(verifiable.DisplayAllDisclosures()) 775 require.NoError(t, err) 776 777 printObject(t, "Display VC - No Limit Disclosure (all fields displayed)", displayVC) 778 779 require.Equal(t, "John", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["given_name"]) 780 require.Equal(t, "Doe", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["family_name"]) 781 require.Equal(t, "johndoe@example.com", displayVC.Subject.([]verifiable.Subject)[0].CustomFields["email"]) 782 783 checkSubmission(t, vp, pd) 784 checkVP(t, vp) 785 }) 786 787 t.Run("SD-JWT: hash algorithm not supported", func(t *testing.T) { 788 required := Required 789 790 pd := &PresentationDefinition{ 791 ID: uuid.New().String(), 792 InputDescriptors: []*InputDescriptor{{ 793 ID: uuid.New().String(), 794 Schema: []*Schema{{ 795 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 796 }}, 797 Constraints: &Constraints{ 798 LimitDisclosure: &required, 799 Fields: []*Field{{ 800 Path: []string{ 801 "$.credentialSubject.given_name", 802 }, 803 }}, 804 }, 805 }}, 806 } 807 808 testVC := getTestVC() 809 810 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 811 require.NoError(t, err) 812 813 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 814 815 sdJwtVC.SDJWTHashAlg = "sha-128" 816 817 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 818 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 819 820 require.Error(t, err) 821 require.Nil(t, vp) 822 require.Contains(t, err.Error(), "_sd_alg 'sha-128' not supported") 823 }) 824 825 t.Run("SD-JWT: invalid JSON path ", func(t *testing.T) { 826 required := Required 827 828 pd := &PresentationDefinition{ 829 ID: uuid.New().String(), 830 InputDescriptors: []*InputDescriptor{{ 831 ID: uuid.New().String(), 832 Schema: []*Schema{{ 833 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 834 }}, 835 Constraints: &Constraints{ 836 LimitDisclosure: &required, 837 Fields: []*Field{{ 838 Path: []string{ 839 "123", 840 }, 841 }}, 842 }, 843 }}, 844 } 845 846 testVC := getTestVC() 847 848 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 849 require.NoError(t, err) 850 851 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 852 853 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 854 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 855 856 require.Error(t, err) 857 require.Nil(t, vp) 858 require.Contains(t, err.Error(), "Expected $ or @ at start of path instead of U+0031") 859 }) 860 861 t.Run("SD-JWT: Limit Disclosure (credentials don't meet requirement)", func(t *testing.T) { 862 required := Required 863 864 pd := &PresentationDefinition{ 865 ID: uuid.New().String(), 866 InputDescriptors: []*InputDescriptor{{ 867 ID: uuid.New().String(), 868 Schema: []*Schema{{ 869 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 870 }}, 871 Constraints: &Constraints{ 872 LimitDisclosure: &required, 873 Fields: []*Field{{ 874 Path: []string{ 875 "$.credentialSubject.family_name", 876 "$.credentialSubject.given_name", 877 "$.credentialSubject.address.country", 878 }, 879 Predicate: &required, 880 Filter: &Filter{Type: &arrFilterType}, 881 }}, 882 }, 883 }}, 884 } 885 886 testVC := getTestVC() 887 888 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 889 require.NoError(t, err) 890 891 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 892 893 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 894 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 895 896 require.Error(t, err) 897 require.Nil(t, vp) 898 require.Contains(t, err.Error(), "credentials do not satisfy requirements") 899 }) 900 901 t.Run("SD-JWT: No Limit Disclosure (credentials don't meet requirement)", func(t *testing.T) { 902 required := Required 903 904 pd := &PresentationDefinition{ 905 ID: uuid.New().String(), 906 InputDescriptors: []*InputDescriptor{{ 907 ID: uuid.New().String(), 908 Schema: []*Schema{{ 909 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 910 }}, 911 Constraints: &Constraints{ 912 Fields: []*Field{{ 913 Path: []string{ 914 "$.credentialSubject.family_name", 915 "$.credentialSubject.given_name", 916 "$.credentialSubject.address.country", 917 }, 918 Predicate: &required, 919 Filter: &Filter{Type: &arrFilterType}, 920 }}, 921 }, 922 }}, 923 } 924 925 testVC := getTestVC() 926 927 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 928 require.NoError(t, err) 929 930 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 931 932 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 933 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 934 935 require.Error(t, err) 936 require.Nil(t, vp) 937 require.Contains(t, err.Error(), "credentials do not satisfy requirements") 938 }) 939 940 t.Run("SD-JWT: Limit Disclosure with invalid field (credentials don't meet requirement)", func(t *testing.T) { 941 required := Required 942 943 pd := &PresentationDefinition{ 944 ID: uuid.New().String(), 945 InputDescriptors: []*InputDescriptor{{ 946 ID: uuid.New().String(), 947 Schema: []*Schema{{ 948 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 949 }}, 950 Constraints: &Constraints{ 951 LimitDisclosure: &required, 952 Fields: []*Field{{ 953 Path: []string{ 954 "$.credentialSubject.invalid", 955 }, 956 }}, 957 }, 958 }}, 959 } 960 961 testVC := getTestVC() 962 963 ed25519Signer, err := newCryptoSigner(kms.ED25519Type) 964 require.NoError(t, err) 965 966 sdJwtVC := newSdJwtVC(t, testVC, ed25519Signer) 967 968 vp, err := pd.CreateVP([]*verifiable.Credential{sdJwtVC}, 969 lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 970 971 require.Error(t, err) 972 require.Nil(t, vp) 973 require.Contains(t, err.Error(), "credentials do not satisfy requirements") 974 }) 975 976 t.Run("Limit disclosure BBS+", func(t *testing.T) { 977 required := Required 978 979 pd := &PresentationDefinition{ 980 ID: uuid.New().String(), 981 InputDescriptors: []*InputDescriptor{{ 982 Schema: []*Schema{{ 983 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 984 }}, 985 ID: uuid.New().String(), 986 Constraints: &Constraints{ 987 LimitDisclosure: &required, 988 Fields: []*Field{{ 989 Path: []string{"$.credentialSubject.degree.degreeSchool"}, 990 Filter: &Filter{Type: &strFilterType}, 991 }}, 992 }, 993 }}, 994 } 995 996 vc := &verifiable.Credential{ 997 ID: "https://issuer.oidp.uscis.gov/credentials/83627465", 998 Context: []string{ 999 verifiable.ContextURI, 1000 "https://www.w3.org/2018/credentials/examples/v1", 1001 "https://w3id.org/security/bbs/v1", 1002 }, 1003 Types: []string{ 1004 "VerifiableCredential", 1005 "UniversityDegreeCredential", 1006 }, 1007 Subject: verifiable.Subject{ 1008 ID: "did:example:b34ca6cd37bbf23", 1009 CustomFields: map[string]interface{}{ 1010 "name": "Jayden Doe", 1011 "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1", 1012 "degree": map[string]interface{}{ 1013 "degree": "MIT", 1014 "degreeSchool": "MIT school", 1015 "type": "BachelorDegree", 1016 }, 1017 }, 1018 }, 1019 Issued: &util.TimeWrapper{ 1020 Time: time.Now(), 1021 }, 1022 Expired: &util.TimeWrapper{ 1023 Time: time.Now().AddDate(1, 0, 0), 1024 }, 1025 Issuer: verifiable.Issuer{ 1026 ID: "did:example:489398593", 1027 }, 1028 CustomFields: map[string]interface{}{ 1029 "identifier": "83627465", 1030 "name": "Permanent Resident Card", 1031 "description": "Government of Example Permanent Resident Card.", 1032 }, 1033 } 1034 1035 publicKey, privateKey, err := bbs12381g2pub.GenerateKeyPair(sha256.New, nil) 1036 require.NoError(t, err) 1037 1038 srcPublicKey, err := publicKey.Marshal() 1039 require.NoError(t, err) 1040 1041 signer, err := newBBSSigner(privateKey) 1042 require.NoError(t, err) 1043 1044 require.NoError(t, vc.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 1045 SignatureType: "BbsBlsSignature2020", 1046 SignatureRepresentation: verifiable.SignatureProofValue, 1047 Suite: bbsblssignature2020.New(suite.WithSigner(signer)), 1048 VerificationMethod: "did:example:123456#key1", 1049 }, jsonld.WithDocumentLoader(createTestJSONLDDocumentLoader(t)))) 1050 1051 vp, err := pd.CreateVP([]*verifiable.Credential{vc}, lddl, 1052 verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t)), 1053 verifiable.WithPublicKeyFetcher(verifiable.SingleKey(srcPublicKey, "Bls12381G2Key2020")), 1054 ) 1055 require.NoError(t, err) 1056 require.NotNil(t, vp) 1057 require.Equal(t, 1, len(vp.Credentials())) 1058 1059 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 1060 require.True(t, ok) 1061 1062 subject := vc.Subject.([]verifiable.Subject)[0] 1063 degree := subject.CustomFields["degree"] 1064 require.NotNil(t, degree) 1065 1066 degreeMap, ok := degree.(map[string]interface{}) 1067 require.True(t, ok) 1068 1069 require.Equal(t, "MIT school", degreeMap["degreeSchool"]) 1070 require.Equal(t, "BachelorDegree", degreeMap["type"]) 1071 require.Empty(t, degreeMap["degree"]) 1072 require.Equal(t, "did:example:b34ca6cd37bbf23", subject.ID) 1073 require.Empty(t, subject.CustomFields["spouse"]) 1074 require.Empty(t, vc.CustomFields["name"]) 1075 1076 require.NotEmpty(t, vc.Proofs) 1077 1078 checkSubmission(t, vp, pd) 1079 checkVP(t, vp) 1080 }) 1081 1082 t.Run("Predicate and limit disclosure BBS+ (no proof)", func(t *testing.T) { 1083 required := Required 1084 1085 pd := &PresentationDefinition{ 1086 ID: uuid.New().String(), 1087 InputDescriptors: []*InputDescriptor{{ 1088 Schema: []*Schema{{ 1089 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1090 }}, 1091 ID: uuid.New().String(), 1092 Constraints: &Constraints{ 1093 LimitDisclosure: &required, 1094 Fields: []*Field{{ 1095 Path: []string{"$.credentialSubject.givenName", "$.credentialSubject.familyName"}, 1096 Filter: &Filter{Type: &strFilterType}, 1097 Predicate: &required, 1098 }, { 1099 Path: []string{"$.credentialSubject.type"}, 1100 Filter: &Filter{Type: &arrFilterType}, 1101 }}, 1102 }, 1103 }}, 1104 } 1105 1106 vc := &verifiable.Credential{ 1107 ID: "https://issuer.oidp.uscis.gov/credentials/83627465", 1108 Context: []string{ 1109 verifiable.ContextURI, 1110 "https://w3id.org/citizenship/v1", 1111 "https://w3id.org/security/bbs/v1", 1112 }, 1113 Types: []string{ 1114 "VerifiableCredential", 1115 "PermanentResidentCard", 1116 }, 1117 Subject: verifiable.Subject{ 1118 ID: "did:example:b34ca6cd37bbf23", 1119 CustomFields: map[string]interface{}{ 1120 "type": []string{ 1121 "PermanentResident", 1122 "Person", 1123 }, 1124 "givenName": "JOHN", 1125 "familyName": "SMITH", 1126 "gender": "Male", 1127 "image": "data:image/png;base64,iVBORw0KGgokJggg==", 1128 "residentSince": "2015-01-01", 1129 "lprCategory": "C09", 1130 "lprNumber": "999-999-999", 1131 "commuterClassification": "C1", 1132 "birthCountry": "Bahamas", 1133 "birthDate": "1958-07-17", 1134 }, 1135 }, 1136 Issued: &util.TimeWrapper{ 1137 Time: time.Now(), 1138 }, 1139 Expired: &util.TimeWrapper{ 1140 Time: time.Now().AddDate(1, 0, 0), 1141 }, 1142 Issuer: verifiable.Issuer{ 1143 ID: "did:example:489398593", 1144 }, 1145 CustomFields: map[string]interface{}{ 1146 "identifier": "83627465", 1147 "name": "Permanent Resident Card", 1148 "description": "Government of Example Permanent Resident Card.", 1149 }, 1150 } 1151 1152 publicKey, privateKey, err := bbs12381g2pub.GenerateKeyPair(sha256.New, nil) 1153 require.NoError(t, err) 1154 1155 srcPublicKey, err := publicKey.Marshal() 1156 require.NoError(t, err) 1157 1158 signer, err := newBBSSigner(privateKey) 1159 require.NoError(t, err) 1160 1161 require.NoError(t, vc.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 1162 SignatureType: "BbsBlsSignature2020", 1163 SignatureRepresentation: verifiable.SignatureProofValue, 1164 Suite: bbsblssignature2020.New(suite.WithSigner(signer)), 1165 VerificationMethod: "did:example:123456#key1", 1166 }, jsonld.WithDocumentLoader(createTestJSONLDDocumentLoader(t)))) 1167 1168 vp, err := pd.CreateVP([]*verifiable.Credential{vc}, lddl, 1169 verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t)), 1170 verifiable.WithPublicKeyFetcher(verifiable.SingleKey(srcPublicKey, "Bls12381G2Key2020")), 1171 ) 1172 require.NoError(t, err) 1173 require.NotNil(t, vp) 1174 require.Equal(t, 1, len(vp.Credentials())) 1175 1176 vc, ok := vp.Credentials()[0].(*verifiable.Credential) 1177 require.True(t, ok) 1178 1179 require.Equal(t, true, vc.Subject.([]verifiable.Subject)[0].CustomFields["givenName"]) 1180 require.Equal(t, true, vc.Subject.([]verifiable.Subject)[0].CustomFields["familyName"]) 1181 require.Empty(t, vc.Subject.([]verifiable.Subject)[0].CustomFields["gender"]) 1182 require.Empty(t, vc.Proofs) 1183 1184 checkSubmission(t, vp, pd) 1185 checkVP(t, vp) 1186 }) 1187 1188 t.Run("Predicate (marshal error)", func(t *testing.T) { 1189 pd := &PresentationDefinition{ 1190 ID: uuid.New().String(), 1191 InputDescriptors: []*InputDescriptor{{ 1192 ID: uuid.New().String(), 1193 Schema: []*Schema{{ 1194 URI: verifiable.ContextID, 1195 }}, 1196 Constraints: &Constraints{ 1197 Fields: []*Field{{ 1198 Path: []string{"$.last_name"}, 1199 Filter: &Filter{Type: &strFilterType}, 1200 }}, 1201 }, 1202 }}, 1203 } 1204 1205 vp, err := pd.CreateVP([]*verifiable.Credential{ 1206 { 1207 Context: []string{verifiable.ContextURI}, 1208 Types: []string{verifiable.VCType}, 1209 ID: uuid.New().String(), 1210 CustomFields: map[string]interface{}{ 1211 "first_name": make(chan struct{}), 1212 "last_name": "Jon", 1213 }, 1214 }, 1215 }, lddl) 1216 1217 require.EqualError(t, err, errMsgSchema) 1218 require.Nil(t, vp) 1219 }) 1220 1221 t.Run("No matches (path)", func(t *testing.T) { 1222 pd := &PresentationDefinition{ 1223 ID: uuid.New().String(), 1224 InputDescriptors: []*InputDescriptor{{ 1225 ID: uuid.New().String(), 1226 Schema: []*Schema{{ 1227 URI: verifiable.ContextID, 1228 }}, 1229 Constraints: &Constraints{ 1230 Fields: []*Field{{ 1231 Path: []string{"$.first_name", "$.last_name"}, 1232 }}, 1233 }, 1234 }}, 1235 } 1236 1237 vp, err := pd.CreateVP([]*verifiable.Credential{ 1238 { 1239 Context: []string{verifiable.ContextURI}, 1240 Types: []string{verifiable.VCType}, 1241 ID: uuid.New().String(), 1242 CustomFields: map[string]interface{}{ 1243 "first_name": "Jesse", 1244 }, 1245 }, 1246 { 1247 ID: uuid.New().String(), 1248 CustomFields: map[string]interface{}{ 1249 "last_name": "Travis", 1250 }, 1251 }, 1252 }, lddl) 1253 1254 require.EqualError(t, err, errMsgSchema) 1255 require.Nil(t, vp) 1256 }) 1257 1258 t.Run("No matches (one field path)", func(t *testing.T) { 1259 pd := &PresentationDefinition{ 1260 ID: uuid.New().String(), 1261 InputDescriptors: []*InputDescriptor{{ 1262 ID: uuid.New().String(), 1263 Schema: []*Schema{{ 1264 URI: verifiable.ContextID, 1265 }}, 1266 Constraints: &Constraints{ 1267 Fields: []*Field{{ 1268 Path: []string{"$.first_name"}, 1269 }, { 1270 Path: []string{"$.last_name"}, 1271 }}, 1272 }, 1273 }}, 1274 } 1275 1276 vp, err := pd.CreateVP([]*verifiable.Credential{ 1277 { 1278 Context: []string{verifiable.ContextURI}, 1279 Types: []string{verifiable.VCType}, 1280 ID: uuid.New().String(), 1281 CustomFields: map[string]interface{}{ 1282 "first_name": "Jesse", 1283 }, 1284 }, 1285 { 1286 ID: uuid.New().String(), 1287 CustomFields: map[string]interface{}{ 1288 "last_name": "Travis", 1289 }, 1290 }, 1291 }, lddl) 1292 1293 require.EqualError(t, err, errMsgSchema) 1294 require.Nil(t, vp) 1295 }) 1296 1297 t.Run("Matches one credentials (two fields)", func(t *testing.T) { 1298 issuerID := uuid.New().String() 1299 1300 pd := &PresentationDefinition{ 1301 ID: uuid.New().String(), 1302 InputDescriptors: []*InputDescriptor{{ 1303 ID: uuid.New().String(), 1304 Schema: []*Schema{{ 1305 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1306 }}, 1307 Constraints: &Constraints{ 1308 SubjectIsIssuer: &subIsIssuerRequired, 1309 Fields: []*Field{{ 1310 Path: []string{"$.first_name"}, 1311 Filter: &Filter{Type: &strFilterType}, 1312 }, { 1313 Path: []string{"$.last_name"}, 1314 Filter: &Filter{Type: &strFilterType}, 1315 }}, 1316 }, 1317 }}, 1318 } 1319 1320 vp, err := pd.CreateVP([]*verifiable.Credential{ 1321 { 1322 Context: []string{verifiable.ContextURI}, 1323 Types: []string{verifiable.VCType}, 1324 ID: uuid.New().String(), 1325 Subject: map[string]interface{}{}, 1326 CustomFields: map[string]interface{}{ 1327 "first_name": "Jesse", 1328 }, 1329 }, { 1330 Context: []string{verifiable.ContextURI}, 1331 Types: []string{verifiable.VCType}, 1332 ID: uuid.New().String(), 1333 Subject: verifiable.Subject{ID: issuerID}, 1334 Issuer: verifiable.Issuer{ID: issuerID}, 1335 CustomFields: map[string]interface{}{ 1336 "first_name": "Jesse", 1337 "last_name": "Travis", 1338 }, 1339 }, 1340 }, lddl) 1341 1342 require.NoError(t, err) 1343 require.NotNil(t, vp) 1344 require.Equal(t, 1, len(vp.Credentials())) 1345 1346 checkSubmission(t, vp, pd) 1347 checkVP(t, vp) 1348 }) 1349 1350 t.Run("Matches one credentials (three fields - disclosure)", func(t *testing.T) { 1351 issuerID := "did:example:76e12ec712ebc6f1c221ebfeb1f" 1352 required := Required 1353 1354 pd := &PresentationDefinition{ 1355 ID: uuid.New().String(), 1356 InputDescriptors: []*InputDescriptor{{ 1357 ID: uuid.New().String(), 1358 Schema: []*Schema{{ 1359 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1360 }}, 1361 Constraints: &Constraints{ 1362 SubjectIsIssuer: &subIsIssuerRequired, 1363 LimitDisclosure: &required, 1364 Fields: []*Field{{ 1365 Path: []string{"$.first_name"}, 1366 Filter: &Filter{Type: &strFilterType}, 1367 }, { 1368 Path: []string{"$.issuer"}, 1369 Filter: &Filter{Type: &strFilterType}, 1370 }, { 1371 Path: []string{"$.all[*].authors[*].name"}, 1372 Filter: &Filter{ 1373 Type: &arrFilterType, 1374 }, 1375 }}, 1376 }, 1377 }}, 1378 } 1379 1380 vp, err := pd.CreateVP([]*verifiable.Credential{ 1381 { 1382 Context: []string{verifiable.ContextURI}, 1383 Types: []string{verifiable.VCType}, 1384 ID: uuid.New().String(), 1385 Subject: []map[string]interface{}{{}}, 1386 Issuer: verifiable.Issuer{ID: uuid.New().String()}, 1387 CustomFields: map[string]interface{}{ 1388 "last_name": "Travis", 1389 }, 1390 }, 1391 { 1392 ID: "http://example.edu/credentials/1872", 1393 Context: []string{verifiable.ContextURI}, 1394 Types: []string{"VerifiableCredential"}, 1395 Subject: []map[string]interface{}{{"id": issuerID}}, 1396 Issuer: verifiable.Issuer{ID: issuerID}, 1397 Issued: &util.TimeWrapper{ 1398 Time: time.Now(), 1399 }, 1400 CustomFields: map[string]interface{}{ 1401 "first_name": "Jesse", 1402 "ssn": "000-00-000", 1403 "last_name": "Travis", 1404 "all": []interface{}{ 1405 map[string]interface{}{ 1406 "authors": []interface{}{map[string]interface{}{ 1407 "name": "Andrew", 1408 "license": "yes", 1409 }, map[string]interface{}{ 1410 "name": "Jessy", 1411 "license": "no", 1412 }}, 1413 }, 1414 map[string]interface{}{ 1415 "authors": []interface{}{map[string]interface{}{ 1416 "license": "unknown", 1417 }}, 1418 }, 1419 map[string]interface{}{ 1420 "authors": []interface{}{map[string]interface{}{ 1421 "name": "Bob", 1422 "license": "yes", 1423 }, map[string]interface{}{ 1424 "name": "Carol", 1425 "license": "no", 1426 }}, 1427 }, 1428 }, 1429 }, 1430 }, 1431 }, lddl, verifiable.WithJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 1432 1433 require.NoError(t, err) 1434 require.NotNil(t, vp) 1435 require.Equal(t, 1, len(vp.Credentials())) 1436 1437 cred, ok := vp.Credentials()[0].(*verifiable.Credential) 1438 require.True(t, ok) 1439 require.NotEmpty(t, cred.Issuer) 1440 1441 require.EqualValues(t, []interface{}{ 1442 map[string]interface{}{ 1443 "authors": []interface{}{map[string]interface{}{ 1444 "name": "Andrew", 1445 }, map[string]interface{}{ 1446 "name": "Jessy", 1447 }}, 1448 }, 1449 map[string]interface{}{ 1450 "authors": []interface{}{map[string]interface{}{ 1451 "name": "Bob", 1452 }, map[string]interface{}{ 1453 "name": "Carol", 1454 }}, 1455 }, 1456 }, cred.CustomFields["all"]) 1457 1458 checkSubmission(t, vp, pd) 1459 checkVP(t, vp) 1460 }) 1461 1462 t.Run("Create new credential (error)", func(t *testing.T) { 1463 required := Required 1464 1465 pd := &PresentationDefinition{ 1466 ID: uuid.New().String(), 1467 InputDescriptors: []*InputDescriptor{{ 1468 ID: uuid.New().String(), 1469 Schema: []*Schema{{ 1470 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1471 }}, 1472 Constraints: &Constraints{ 1473 LimitDisclosure: &required, 1474 Fields: []*Field{{ 1475 Path: []string{"$.first_name"}, 1476 Filter: &Filter{ 1477 Type: &strFilterType, 1478 Pattern: "^Jesse", 1479 }, 1480 }}, 1481 }, 1482 }}, 1483 } 1484 1485 vp, err := pd.CreateVP([]*verifiable.Credential{ 1486 { 1487 Context: []string{verifiable.ContextURI}, 1488 Types: []string{verifiable.VCType}, 1489 ID: uuid.New().String(), 1490 Issuer: verifiable.Issuer{CustomFields: map[string]interface{}{"k": "v"}}, 1491 CustomFields: map[string]interface{}{ 1492 "first_name": "Jesse", 1493 }, 1494 }, 1495 }, lddl) 1496 1497 require.Error(t, err) 1498 require.True(t, strings.HasPrefix(err.Error(), "create new credential")) 1499 require.Nil(t, vp) 1500 }) 1501 1502 t.Run("Matches one credentials (field pattern)", func(t *testing.T) { 1503 issuerID := uuid.New().String() 1504 1505 pd := &PresentationDefinition{ 1506 ID: uuid.New().String(), 1507 InputDescriptors: []*InputDescriptor{{ 1508 ID: uuid.New().String(), 1509 Schema: []*Schema{{ 1510 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1511 }}, 1512 Constraints: &Constraints{ 1513 SubjectIsIssuer: &subIsIssuerRequired, 1514 Fields: []*Field{{ 1515 Path: []string{"$.first_name"}, 1516 Filter: &Filter{ 1517 Type: &strFilterType, 1518 Pattern: "^Jesse", 1519 }, 1520 }}, 1521 }, 1522 }}, 1523 } 1524 1525 vp, err := pd.CreateVP([]*verifiable.Credential{ 1526 { 1527 Context: []string{verifiable.ContextURI}, 1528 Types: []string{verifiable.VCType}, 1529 ID: uuid.New().String(), 1530 Subject: map[string]interface{}{"id": issuerID}, 1531 Issuer: verifiable.Issuer{ID: issuerID}, 1532 CustomFields: map[string]interface{}{ 1533 "first_name": "Jesse", 1534 }, 1535 }, 1536 { 1537 Context: []string{verifiable.ContextURI}, 1538 Types: []string{verifiable.VCType}, 1539 ID: uuid.New().String(), 1540 Subject: map[string]interface{}{"id": 123}, 1541 CustomFields: map[string]interface{}{ 1542 "first_name": "Travis", 1543 "last_name": "Jesse", 1544 }, 1545 }, 1546 }, lddl) 1547 1548 require.NoError(t, err) 1549 require.NotNil(t, vp) 1550 require.Equal(t, 1, len(vp.Credentials())) 1551 1552 checkSubmission(t, vp, pd) 1553 checkVP(t, vp) 1554 }) 1555 1556 t.Run("Matches one credentials", func(t *testing.T) { 1557 issuerID := uuid.New().String() 1558 1559 pd := &PresentationDefinition{ 1560 ID: uuid.New().String(), 1561 InputDescriptors: []*InputDescriptor{{ 1562 ID: uuid.New().String(), 1563 Schema: []*Schema{{ 1564 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1565 }}, 1566 Constraints: &Constraints{ 1567 SubjectIsIssuer: &subIsIssuerRequired, 1568 Fields: []*Field{{ 1569 Path: []string{"$.first_name", "$.last_name"}, 1570 }}, 1571 }, 1572 }}, 1573 } 1574 1575 vp, err := pd.CreateVP([]*verifiable.Credential{ 1576 { 1577 Context: []string{verifiable.ContextURI}, 1578 Types: []string{verifiable.VCType}, 1579 ID: uuid.New().String(), 1580 CustomFields: map[string]interface{}{ 1581 "first_name": "Jesse", 1582 }, 1583 }, 1584 { 1585 Context: []string{verifiable.ContextURI}, 1586 Types: []string{verifiable.VCType}, 1587 ID: uuid.New().String(), 1588 Subject: []verifiable.Subject{{ID: issuerID}}, 1589 Issuer: verifiable.Issuer{ID: issuerID}, 1590 CustomFields: map[string]interface{}{ 1591 "first_name": "Jesse", 1592 "last_name": "Travis", 1593 }, 1594 }, 1595 }, lddl) 1596 1597 require.NoError(t, err) 1598 require.NotNil(t, vp) 1599 require.Equal(t, 1, len(vp.Credentials())) 1600 1601 checkSubmission(t, vp, pd) 1602 checkVP(t, vp) 1603 }) 1604 1605 t.Run("Matches one credentials (two descriptors)", func(t *testing.T) { 1606 issuerID := uuid.New().String() 1607 1608 pd := &PresentationDefinition{ 1609 ID: uuid.New().String(), 1610 InputDescriptors: []*InputDescriptor{{ 1611 ID: uuid.New().String(), 1612 Schema: []*Schema{{ 1613 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1614 }}, 1615 Constraints: &Constraints{ 1616 SubjectIsIssuer: &subIsIssuerRequired, 1617 Fields: []*Field{{ 1618 Path: []string{"$.first_name"}, 1619 }, { 1620 Path: []string{"$.last_name"}, 1621 }}, 1622 }, 1623 }, { 1624 ID: uuid.New().String(), 1625 Schema: []*Schema{{ 1626 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1627 }}, 1628 Constraints: &Constraints{ 1629 Fields: []*Field{{ 1630 Path: []string{"$.first_name"}, 1631 }, { 1632 Path: []string{"$.last_name"}, 1633 }}, 1634 }, 1635 }}, 1636 } 1637 1638 vp, err := pd.CreateVP([]*verifiable.Credential{ 1639 { 1640 Context: []string{verifiable.ContextURI}, 1641 Types: []string{verifiable.VCType}, 1642 ID: uuid.New().String(), 1643 Subject: issuerID, 1644 Issuer: verifiable.Issuer{ID: issuerID}, 1645 CustomFields: map[string]interface{}{ 1646 "first_name": "Jesse", 1647 }, 1648 }, 1649 { 1650 Context: []string{verifiable.ContextURI}, 1651 Types: []string{verifiable.VCType}, 1652 ID: uuid.New().String(), 1653 Subject: issuerID, 1654 Issuer: verifiable.Issuer{ID: issuerID}, 1655 CustomFields: map[string]interface{}{ 1656 "first_name": "Jesse", 1657 "last_name": "Travis", 1658 }, 1659 }, 1660 }, lddl) 1661 1662 require.NoError(t, err) 1663 require.NotNil(t, vp) 1664 require.Equal(t, 1, len(vp.Credentials())) 1665 1666 checkSubmission(t, vp, pd) 1667 checkVP(t, vp) 1668 }) 1669 1670 t.Run("Matches two credentials (one descriptor)", func(t *testing.T) { 1671 pd := &PresentationDefinition{ 1672 ID: uuid.New().String(), 1673 InputDescriptors: []*InputDescriptor{{ 1674 ID: uuid.New().String(), 1675 Schema: []*Schema{{ 1676 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1677 }}, 1678 Constraints: &Constraints{ 1679 Fields: []*Field{{ 1680 Path: []string{"$.first_name"}, 1681 }}, 1682 }, 1683 }}, 1684 } 1685 1686 vp, err := pd.CreateVP([]*verifiable.Credential{ 1687 { 1688 Context: []string{verifiable.ContextURI}, 1689 Types: []string{verifiable.VCType}, 1690 ID: uuid.New().String(), 1691 CustomFields: map[string]interface{}{ 1692 "first_name": "Jesse", 1693 }, 1694 }, 1695 { 1696 Context: []string{verifiable.ContextURI}, 1697 Types: []string{verifiable.VCType}, 1698 ID: uuid.New().String(), 1699 CustomFields: map[string]interface{}{ 1700 "first_name": "Jesse", 1701 "last_name": "Travis", 1702 }, 1703 }, 1704 }, lddl) 1705 1706 require.NoError(t, err) 1707 require.NotNil(t, vp) 1708 require.Equal(t, 2, len(vp.Credentials())) 1709 1710 checkSubmission(t, vp, pd) 1711 checkVP(t, vp) 1712 }) 1713 1714 t.Run("Matches two credentials", func(t *testing.T) { 1715 pd := &PresentationDefinition{ 1716 ID: uuid.New().String(), 1717 InputDescriptors: []*InputDescriptor{{ 1718 ID: uuid.New().String(), 1719 Schema: []*Schema{{ 1720 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1721 }}, 1722 }}, 1723 } 1724 1725 vp, err := pd.CreateVP([]*verifiable.Credential{ 1726 { 1727 Context: []string{verifiable.ContextURI}, 1728 Types: []string{verifiable.VCType}, 1729 ID: uuid.New().String(), 1730 }, 1731 { 1732 Context: []string{verifiable.ContextURI}, 1733 Types: []string{verifiable.VCType}, 1734 ID: uuid.New().String(), 1735 }, 1736 }, lddl) 1737 1738 require.NoError(t, err) 1739 require.NotNil(t, vp) 1740 require.Equal(t, 2, len(vp.Credentials())) 1741 1742 checkSubmission(t, vp, pd) 1743 checkVP(t, vp) 1744 }) 1745 1746 t.Run("Matches one credentials (one ignored)", func(t *testing.T) { 1747 pd := &PresentationDefinition{ 1748 ID: uuid.New().String(), 1749 InputDescriptors: []*InputDescriptor{{ 1750 ID: uuid.New().String(), 1751 Schema: []*Schema{{ 1752 URI: "https://example.org/examples#UniversityDegreeCredential", 1753 }}, 1754 }}, 1755 } 1756 1757 vp, err := pd.CreateVP([]*verifiable.Credential{ 1758 { 1759 Context: []string{verifiable.ContextURI}, 1760 Types: []string{verifiable.VCType}, 1761 ID: uuid.New().String(), 1762 }, 1763 { 1764 Context: []string{verifiable.ContextURI, "https://www.w3.org/2018/credentials/examples/v1"}, 1765 Types: []string{verifiable.VCType, "UniversityDegreeCredential"}, 1766 ID: uuid.New().String(), 1767 }, 1768 }, lddl) 1769 1770 require.NoError(t, err) 1771 require.NotNil(t, vp) 1772 require.Equal(t, 1, len(vp.Credentials())) 1773 1774 checkSubmission(t, vp, pd) 1775 checkVP(t, vp) 1776 }) 1777 1778 t.Run("No matches", func(t *testing.T) { 1779 pd := &PresentationDefinition{ 1780 ID: uuid.New().String(), 1781 InputDescriptors: []*InputDescriptor{{ 1782 ID: uuid.New().String(), 1783 Schema: []*Schema{{ 1784 URI: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1785 }}, 1786 }}, 1787 } 1788 1789 vp, err := pd.CreateVP([]*verifiable.Credential{ 1790 { 1791 Context: []string{verifiable.ContextURI}, 1792 Types: []string{verifiable.VCType}, 1793 ID: uuid.New().String(), 1794 Schemas: []verifiable.TypedID{{ 1795 ID: "https://www.w3.org/TR/vc-data-model/2.0/#types", 1796 Type: "JsonSchemaValidator2018", 1797 }}, 1798 }, 1799 { 1800 ID: uuid.New().String(), 1801 Schemas: []verifiable.TypedID{{ 1802 ID: "https://www.w3.org/TR/vc-data-model/3.0/#types", 1803 Type: "JsonSchemaValidator2018", 1804 }}, 1805 }, 1806 }, lddl) 1807 1808 require.EqualError(t, err, errMsgSchema) 1809 require.Nil(t, vp) 1810 }) 1811 1812 t.Run("Matches two descriptors", func(t *testing.T) { 1813 pd := &PresentationDefinition{ 1814 ID: uuid.New().String(), 1815 InputDescriptors: []*InputDescriptor{{ 1816 ID: uuid.New().String(), 1817 Schema: []*Schema{{ 1818 URI: "https://example.org/examples#UniversityDegreeCredential", 1819 }}, 1820 }, { 1821 ID: uuid.New().String(), 1822 Schema: []*Schema{{ 1823 URI: "https://example.org/examples#DocumentVerification", 1824 }}, 1825 }}, 1826 } 1827 1828 vp, err := pd.CreateVP([]*verifiable.Credential{ 1829 { 1830 Context: []string{verifiable.ContextURI, "https://www.w3.org/2018/credentials/examples/v1"}, 1831 Types: []string{verifiable.VCType, "UniversityDegreeCredential"}, 1832 ID: uuid.New().String(), 1833 }, 1834 { 1835 Context: []string{verifiable.ContextURI, "https://trustbloc.github.io/context/vc/examples-v1.jsonld"}, 1836 Types: []string{verifiable.VCType, "DocumentVerification"}, 1837 ID: uuid.New().String(), 1838 }, 1839 }, lddl) 1840 1841 require.NoError(t, err) 1842 require.NotNil(t, vp) 1843 require.Equal(t, 2, len(vp.Credentials())) 1844 1845 checkSubmission(t, vp, pd) 1846 checkVP(t, vp) 1847 }) 1848 1849 t.Run("Does not match one of descriptors", func(t *testing.T) { 1850 pd := &PresentationDefinition{ 1851 ID: uuid.New().String(), 1852 InputDescriptors: []*InputDescriptor{{ 1853 ID: uuid.New().String(), 1854 Schema: []*Schema{{ 1855 URI: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1856 }}, 1857 }, { 1858 ID: uuid.New().String(), 1859 Schema: []*Schema{{ 1860 URI: "https://www.w3.org/TR/vc-data-model/2.0/#types", 1861 }}, 1862 }}, 1863 } 1864 1865 vp, err := pd.CreateVP([]*verifiable.Credential{ 1866 { 1867 Context: []string{verifiable.ContextURI}, 1868 Types: []string{verifiable.VCType}, 1869 ID: uuid.New().String(), 1870 Schemas: []verifiable.TypedID{{ 1871 ID: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1872 Type: "JsonSchemaValidator2018", 1873 }}, 1874 }, 1875 { 1876 Context: []string{verifiable.ContextURI}, 1877 Types: []string{verifiable.VCType}, 1878 ID: uuid.New().String(), 1879 Schemas: []verifiable.TypedID{{ 1880 ID: "https://www.w3.org/TR/vc-data-model/3.0/#types", 1881 Type: "JsonSchemaValidator2018", 1882 }}, 1883 }, 1884 }, lddl) 1885 1886 require.EqualError(t, err, errMsgSchema) 1887 require.Nil(t, vp) 1888 }) 1889 1890 t.Run("Does not match one of descriptors (required)", func(t *testing.T) { 1891 pd := &PresentationDefinition{ 1892 ID: uuid.New().String(), 1893 InputDescriptors: []*InputDescriptor{{ 1894 ID: uuid.New().String(), 1895 Schema: []*Schema{{ 1896 URI: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1897 }}, 1898 }, { 1899 ID: uuid.New().String(), 1900 Schema: []*Schema{{ 1901 URI: "https://www.w3.org/TR/vc-data-model/2.0/#types", 1902 }, { 1903 URI: "https://www.w3.org/TR/vc-data-model/3.0/#types", 1904 Required: true, 1905 }}, 1906 }}, 1907 } 1908 vp, err := pd.CreateVP([]*verifiable.Credential{ 1909 { 1910 Context: []string{verifiable.ContextURI}, 1911 Types: []string{verifiable.VCType}, 1912 ID: uuid.New().String(), 1913 Schemas: []verifiable.TypedID{{ 1914 ID: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1915 Type: "JsonSchemaValidator2018", 1916 }}, 1917 }, 1918 { 1919 Context: []string{verifiable.ContextURI}, 1920 Types: []string{verifiable.VCType}, 1921 ID: uuid.New().String(), 1922 Schemas: []verifiable.TypedID{{ 1923 ID: "https://www.w3.org/TR/vc-data-model/2.0/#types", 1924 }}, 1925 }, 1926 }, lddl) 1927 1928 require.EqualError(t, err, errMsgSchema) 1929 require.Nil(t, vp) 1930 }) 1931 1932 t.Run("Ignores schema that is not required", func(t *testing.T) { 1933 pd := &PresentationDefinition{ 1934 ID: uuid.New().String(), 1935 InputDescriptors: []*InputDescriptor{{ 1936 ID: uuid.New().String(), 1937 Schema: []*Schema{{ 1938 URI: "https://example.org/examples#DocumentVerification", 1939 }}, 1940 }, { 1941 ID: uuid.New().String(), 1942 Schema: []*Schema{{ 1943 URI: "https://www.w3.org/TR/vc-data-model/2.0/#types", 1944 }, { 1945 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1946 Required: true, 1947 }}, 1948 }}, 1949 } 1950 vp, err := pd.CreateVP([]*verifiable.Credential{ 1951 { 1952 Context: []string{verifiable.ContextURI}, 1953 Types: []string{verifiable.VCType}, 1954 ID: uuid.New().String(), 1955 }, 1956 { 1957 Context: []string{verifiable.ContextURI, "https://trustbloc.github.io/context/vc/examples-v1.jsonld"}, 1958 Types: []string{verifiable.VCType, "DocumentVerification"}, 1959 ID: uuid.New().String(), 1960 }, 1961 }, lddl) 1962 1963 require.NoError(t, err) 1964 require.NotNil(t, vp) 1965 require.Equal(t, 2, len(vp.Credentials())) 1966 1967 checkSubmission(t, vp, pd) 1968 checkVP(t, vp) 1969 }) 1970 1971 t.Run("Requires two schemas", func(t *testing.T) { 1972 pd := &PresentationDefinition{ 1973 ID: uuid.New().String(), 1974 InputDescriptors: []*InputDescriptor{{ 1975 ID: uuid.New().String(), 1976 Schema: []*Schema{{ 1977 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1978 }}, 1979 }, { 1980 ID: uuid.New().String(), 1981 Schema: []*Schema{{ 1982 URI: "https://example.org/examples#UniversityDegreeCredential", 1983 Required: true, 1984 }, { 1985 URI: "https://example.org/examples#DocumentVerification", 1986 Required: true, 1987 }}, 1988 }}, 1989 } 1990 vp, err := pd.CreateVP([]*verifiable.Credential{ 1991 { 1992 Context: []string{verifiable.ContextURI}, 1993 Types: []string{verifiable.VCType}, 1994 ID: uuid.New().String(), 1995 Schemas: []verifiable.TypedID{{ 1996 ID: "https://www.w3.org/TR/vc-data-model/1.0/#types", 1997 Type: "JsonSchemaValidator2018", 1998 }}, 1999 }, 2000 { 2001 Context: []string{ 2002 verifiable.ContextURI, 2003 "https://www.w3.org/2018/credentials/examples/v1", 2004 "https://trustbloc.github.io/context/vc/examples-v1.jsonld", 2005 }, 2006 Types: []string{verifiable.VCType, "UniversityDegreeCredential", "DocumentVerification"}, 2007 ID: uuid.New().String(), 2008 }, 2009 }, lddl) 2010 2011 require.NoError(t, err) 2012 require.NotNil(t, vp) 2013 require.Equal(t, 2, len(vp.Credentials())) 2014 2015 checkSubmission(t, vp, pd) 2016 checkVP(t, vp) 2017 }) 2018 } 2019 2020 func TestPresentationDefinition_CreateVPArray(t *testing.T) { 2021 lddl := createTestJSONLDDocumentLoader(t) 2022 2023 t.Run("Matches two descriptors", func(t *testing.T) { 2024 pd := &PresentationDefinition{ 2025 ID: uuid.New().String(), 2026 InputDescriptors: []*InputDescriptor{{ 2027 ID: uuid.New().String(), 2028 Schema: []*Schema{{ 2029 URI: "https://example.org/examples#UniversityDegreeCredential", 2030 }}, 2031 }, { 2032 ID: uuid.New().String(), 2033 Schema: []*Schema{{ 2034 URI: "https://example.org/examples#DocumentVerification", 2035 }}, 2036 }}, 2037 } 2038 2039 vpList, ps, err := pd.CreateVPArray([]*verifiable.Credential{ 2040 { 2041 Context: []string{verifiable.ContextURI, "https://www.w3.org/2018/credentials/examples/v1"}, 2042 Types: []string{verifiable.VCType, "UniversityDegreeCredential"}, 2043 ID: uuid.New().String(), 2044 }, 2045 { 2046 Context: []string{verifiable.ContextURI, "https://trustbloc.github.io/context/vc/examples-v1.jsonld"}, 2047 Types: []string{verifiable.VCType, "DocumentVerification"}, 2048 ID: uuid.New().String(), 2049 }, 2050 }, lddl) 2051 2052 require.NoError(t, err) 2053 require.NotNil(t, vpList) 2054 require.Len(t, vpList, 2) 2055 2056 checkExternalSubmission(t, vpList, ps, pd) 2057 2058 for _, vp := range vpList { 2059 checkVP(t, vp) 2060 } 2061 }) 2062 } 2063 2064 func createEdDSAJWS(t *testing.T, cred *verifiable.Credential, signer verifiable.Signer, 2065 keyID string, minimize bool) string { 2066 t.Helper() 2067 2068 jwtClaims, err := cred.JWTClaims(minimize) 2069 require.NoError(t, err) 2070 vcJWT, err := jwtClaims.MarshalJWS(verifiable.EdDSA, signer, cred.Issuer.ID+"#keys-"+keyID) 2071 require.NoError(t, err) 2072 2073 return vcJWT 2074 } 2075 2076 func getTestVCWithContext(ctx []string) *verifiable.Credential { 2077 subject := map[string]interface{}{ 2078 "id": uuid.New().String(), 2079 "sub": "john_doe_42", 2080 "given_name": "John", 2081 "family_name": "Doe", 2082 "email": "johndoe@example.com", 2083 "phone_number": "+1-202-555-0101", 2084 "birthdate": "1940-01-01", 2085 "address": map[string]interface{}{ 2086 "street_address": "123 Main St", 2087 "locality": "Anytown", 2088 "region": "Anystate", 2089 "country": "US", 2090 }, 2091 } 2092 2093 vc := verifiable.Credential{ 2094 Context: []string{verifiable.ContextURI}, 2095 Types: []string{verifiable.VCType}, 2096 ID: "http://example.edu/credentials/1872", 2097 Issued: &util.TimeWrapper{ 2098 Time: time.Now(), 2099 }, 2100 Issuer: verifiable.Issuer{ 2101 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 2102 }, 2103 Schemas: []verifiable.TypedID{{ 2104 ID: "https://www.w3.org/TR/vc-data-model/2.0/#types", 2105 Type: "JsonSchemaValidator2018", 2106 }}, 2107 Subject: subject, 2108 } 2109 2110 if ctx != nil { 2111 vc.Context = append(vc.Context, ctx...) 2112 } 2113 2114 return &vc 2115 } 2116 2117 func getTestVC() *verifiable.Credential { 2118 return getTestVCWithContext(nil) 2119 } 2120 2121 func newSdJwtVC(t *testing.T, vc *verifiable.Credential, signer signature.Signer) *verifiable.Credential { 2122 t.Helper() 2123 2124 pubKey := signer.PublicKeyBytes() 2125 2126 issuer, verMethod := fingerprint.CreateDIDKeyByCode(fingerprint.ED25519PubKeyMultiCodec, pubKey) 2127 2128 vc.Issuer = verifiable.Issuer{ID: issuer} 2129 2130 jwsAlgo, err := verifiable.KeyTypeToJWSAlgo(kms.ED25519Type) 2131 require.NoError(t, err) 2132 2133 algName, err := jwsAlgo.Name() 2134 require.NoError(t, err) 2135 2136 combinedFormatForIssuance, err := vc.MakeSDJWT(verifiable.GetJWTSigner(signer, algName), verMethod) 2137 require.NoError(t, err) 2138 2139 parsed, err := verifiable.ParseCredential([]byte(combinedFormatForIssuance), 2140 verifiable.WithPublicKeyFetcher(holderPublicKeyFetcher(pubKey))) 2141 require.NoError(t, err) 2142 2143 return parsed 2144 } 2145 2146 func holderPublicKeyFetcher(pubKeyBytes []byte) verifiable.PublicKeyFetcher { 2147 return func(issuerID, keyID string) (*verifier.PublicKey, error) { 2148 return &verifier.PublicKey{ 2149 Type: kms.RSARS256, 2150 Value: pubKeyBytes, 2151 }, nil 2152 } 2153 } 2154 2155 func createKMS() (*localkms.LocalKMS, error) { 2156 p, err := mockkms.NewProviderForKMS(storage.NewMockStoreProvider(), &noop.NoLock{}) 2157 if err != nil { 2158 return nil, err 2159 } 2160 2161 return localkms.New("local-lock://custom/master/key/", p) 2162 } 2163 2164 func newCryptoSigner(keyType kms.KeyType) (signature.Signer, error) { // nolint:unparam 2165 localKMS, err := createKMS() 2166 if err != nil { 2167 return nil, err 2168 } 2169 2170 tinkCrypto, err := tinkcrypto.New() 2171 if err != nil { 2172 return nil, err 2173 } 2174 2175 return signature.NewCryptoSigner(tinkCrypto, localKMS, keyType) 2176 } 2177 2178 func checkSubmission(t *testing.T, vp *verifiable.Presentation, pd *PresentationDefinition) { 2179 t.Helper() 2180 2181 ps, ok := vp.CustomFields["presentation_submission"].(*PresentationSubmission) 2182 require.True(t, ok) 2183 require.NotEmpty(t, ps.ID) 2184 require.Equal(t, ps.DefinitionID, pd.ID) 2185 2186 src, err := json.Marshal(vp) 2187 require.NoError(t, err) 2188 2189 vpAsMap := map[string]interface{}{} 2190 require.NoError(t, json.Unmarshal(src, &vpAsMap)) 2191 2192 builder := gval.Full(jsonpath.PlaceholderExtension()) 2193 2194 for _, descriptor := range ps.DescriptorMap { 2195 require.NotEmpty(t, descriptor.ID) 2196 require.NotEmpty(t, descriptor.Path) 2197 require.NotEmpty(t, descriptor.Format) 2198 2199 path, err := builder.NewEvaluable(descriptor.Path) 2200 require.NoError(t, err) 2201 _, err = path(context.TODO(), vpAsMap) 2202 require.NoError(t, err) 2203 } 2204 } 2205 2206 func checkExternalSubmission( 2207 t *testing.T, 2208 vpList []*verifiable.Presentation, 2209 ps *PresentationSubmission, 2210 pd *PresentationDefinition, 2211 ) { 2212 t.Helper() 2213 2214 require.NotEmpty(t, ps.ID) 2215 require.Equal(t, ps.DefinitionID, pd.ID) 2216 2217 src, err := json.Marshal(vpList) 2218 require.NoError(t, err) 2219 2220 rawVPList := []interface{}{} 2221 require.NoError(t, json.Unmarshal(src, &rawVPList)) 2222 2223 builder := gval.Full(jsonpath.PlaceholderExtension()) 2224 2225 for _, descriptor := range ps.DescriptorMap { 2226 require.NotEmpty(t, descriptor.ID) 2227 require.NotEmpty(t, descriptor.Path) 2228 require.NotEmpty(t, descriptor.Format) 2229 2230 path, err := builder.NewEvaluable(descriptor.Path) 2231 require.NoError(t, err) 2232 _, err = path(context.TODO(), rawVPList) 2233 require.NoError(t, err) 2234 } 2235 } 2236 2237 func checkVP(t *testing.T, vp *verifiable.Presentation) { 2238 t.Helper() 2239 2240 src, err := json.Marshal(vp) 2241 require.NoError(t, err) 2242 2243 _, err = verifiable.ParsePresentation(src, 2244 verifiable.WithPresDisabledProofCheck(), 2245 verifiable.WithPresJSONLDDocumentLoader(createTestJSONLDDocumentLoader(t))) 2246 require.NoError(t, err) 2247 } 2248 2249 func parseJSONFile(t *testing.T, name string, v interface{}) { 2250 t.Helper() 2251 2252 jf, err := os.Open(name) // nolint: gosec 2253 if err != nil { 2254 t.Error(err) 2255 } 2256 2257 defer func() { 2258 if err = jf.Close(); err != nil { 2259 t.Error(err) 2260 } 2261 }() 2262 2263 byteValue, err := ioutil.ReadAll(jf) 2264 if err != nil { 2265 t.Error(err) 2266 } 2267 2268 if err = json.Unmarshal(byteValue, &v); err != nil { 2269 t.Error(err) 2270 } 2271 } 2272 2273 type bbsSigner struct { 2274 privateKey []byte 2275 } 2276 2277 func newBBSSigner(key *bbs12381g2pub.PrivateKey) (*bbsSigner, error) { 2278 src, err := key.Marshal() 2279 if err != nil { 2280 return nil, err 2281 } 2282 2283 return &bbsSigner{privateKey: src}, nil 2284 } 2285 2286 func (s *bbsSigner) Sign(data []byte) ([]byte, error) { 2287 return bbs12381g2pub.New().Sign(s.textToLines(string(data)), s.privateKey) 2288 } 2289 2290 func (s *bbsSigner) Alg() string { 2291 return "" 2292 } 2293 2294 func (s *bbsSigner) textToLines(txt string) [][]byte { 2295 lines := strings.Split(txt, "\n") 2296 linesBytes := make([][]byte, 0, len(lines)) 2297 2298 for i := range lines { 2299 if strings.TrimSpace(lines[i]) != "" { 2300 linesBytes = append(linesBytes, []byte(lines[i])) 2301 } 2302 } 2303 2304 return linesBytes 2305 } 2306 2307 func createTestJSONLDDocumentLoader(t *testing.T) *ld.DocumentLoader { 2308 t.Helper() 2309 2310 loader, err := ldtestutil.DocumentLoader() 2311 require.NoError(t, err) 2312 2313 return loader 2314 } 2315 2316 func prettyPrint(msg []byte) (string, error) { 2317 var prettyJSON bytes.Buffer 2318 2319 err := json.Indent(&prettyJSON, msg, "", "\t") 2320 if err != nil { 2321 return "", err 2322 } 2323 2324 return prettyJSON.String(), nil 2325 } 2326 2327 func printObject(t *testing.T, name string, obj interface{}) { 2328 t.Helper() 2329 2330 objBytes, err := json.Marshal(obj) 2331 require.NoError(t, err) 2332 2333 prettyJSON, err := prettyPrint(objBytes) 2334 require.NoError(t, err) 2335 2336 fmt.Println(name + ":") 2337 fmt.Println(prettyJSON) 2338 }