@sphereon/ssi-sdk.sd-jwt 0.32.1-next.18 → 0.32.1-next.287

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/action-handler.d.ts.map +1 -1
  2. package/dist/action-handler.js +39 -8
  3. package/dist/action-handler.js.map +1 -1
  4. package/dist/defaultCallbacks.d.ts +2 -2
  5. package/dist/defaultCallbacks.d.ts.map +1 -1
  6. package/dist/defaultCallbacks.js +1 -1
  7. package/dist/defaultCallbacks.js.map +1 -1
  8. package/dist/types.d.ts +4 -4
  9. package/dist/types.d.ts.map +1 -1
  10. package/dist/utils.d.ts +15 -2
  11. package/dist/utils.d.ts.map +1 -1
  12. package/dist/utils.js +29 -4
  13. package/dist/utils.js.map +1 -1
  14. package/package.json +20 -20
  15. package/src/__tests__/resources/BoardingPassCredential-vct.json +196 -0
  16. package/src/__tests__/resources/LoyaltyProgram Account VC Schema V0.1 sd-jwt-schema.json +97 -0
  17. package/src/__tests__/resources/LoyaltyProgramAccountCredential-vct.json +126 -0
  18. package/src/__tests__/resources/boarding Pass VC Schema V1.0 sd-jwt.json +156 -0
  19. package/src/__tests__/resources/boardingpass-logo.png +0 -0
  20. package/src/__tests__/resources/boardingpass.svg +1 -0
  21. package/src/__tests__/resources/e-passport.svg +1 -0
  22. package/src/__tests__/resources/ePassport VC Schema V1.0.sd-jwt.json +226 -0
  23. package/src/__tests__/resources/ePassportCredential-vct.json +226 -0
  24. package/src/__tests__/resources/epassport-logo.png +0 -0
  25. package/src/__tests__/resources/loyaltyprogramaccount-icon.png +0 -0
  26. package/src/__tests__/resources/loyaltyprogramaccount.png +0 -0
  27. package/src/__tests__/resources/loyaltyprogramaccount.svg +1 -0
  28. package/src/__tests__/resources/travel-agency VC Employee v0.1 sd-jwt-schema.json +115 -0
  29. package/src/__tests__/resources/travel-agency-EmployeeAgencyCredential-vct.json +146 -0
  30. package/src/__tests__/resources/travel-agency-vc-employee-logo.png +0 -0
  31. package/src/__tests__/resources/travel-agency-vc-employee.svg +1 -0
  32. package/src/__tests__/sd-jwt-integrity.test.ts +100 -0
  33. package/src/__tests__/sd-jwt.test.ts +4 -4
  34. package/src/action-handler.ts +51 -18
  35. package/src/defaultCallbacks.ts +5 -4
  36. package/src/types.ts +4 -4
  37. package/src/utils.ts +48 -4
@@ -0,0 +1,146 @@
1
+ {
2
+ "name": "Employee Agency Verifiable Credential",
3
+ "schema_uri": "https://iata.trustregistry.nborbit.ca/.well-known/schema/employee.json",
4
+ "schema_uri#integrity": "sha256-WFMhTljMTe7UrWbol6llL3T0K4VkxPgd0QoXzQHMKNQ",
5
+ "vct": "https://iata.trustregistry.nborbit.ca/employee",
6
+ "description": "A Verifiable Credential for employees working at a travel agency",
7
+ "display": [
8
+ {
9
+ "description": "A Verifiable Credential for employees working at a travel agency",
10
+ "lang": "en-US",
11
+ "name": "Employee Agency Verifiable Credential",
12
+ "rendering": {
13
+ "simple": {
14
+ "background_color": "#3140f5",
15
+ "logo": {
16
+ "alt_text": "Employee Agency Verifiable Credential",
17
+ "uri": "https://iata.trustregistry.nborbit.ca/logo/travel-agency-vc-employee-logo.png",
18
+ "uri#integrity": "sha256-eteLIlHRkfyG6Apq7qHORaT9BFYC64kfkseerzYGVx0"
19
+ },
20
+ "text_color": "#F9F9F9"
21
+ },
22
+ "svg_template": {
23
+ "properties": {
24
+ "color_scheme": "light",
25
+ "contrast": "high",
26
+ "orientation": "landscape"
27
+ },
28
+ "uri": "https://iata.trustregistry.nborbit.ca/svg/travel-agency-vc-employee.svg",
29
+ "uri#integrity": "sha256-kEWNMcivN2JGiMlSEt47SuAlTQRPQ7Gflas0S5NTD/s"
30
+ }
31
+ }
32
+ }
33
+ ],
34
+ "claims": [
35
+ {
36
+ "display": [
37
+ {
38
+ "description": "Employee Information",
39
+ "label": "Employee",
40
+ "lang": "en-US"
41
+ }
42
+ ],
43
+ "path": ["employee"]
44
+ },
45
+ {
46
+ "display": [
47
+ {
48
+ "description": "Title prefix",
49
+ "label": "Subject Salutation",
50
+ "lang": "en-US"
51
+ }
52
+ ],
53
+ "path": ["employee", "salutation"]
54
+ },
55
+ {
56
+ "display": [
57
+ {
58
+ "description": "First Name",
59
+ "label": "Given Name",
60
+ "lang": "en-US"
61
+ }
62
+ ],
63
+ "path": ["employee", "givenName"]
64
+ },
65
+ {
66
+ "display": [
67
+ {
68
+ "description": "Surname",
69
+ "label": "Surname",
70
+ "lang": "en-US"
71
+ }
72
+ ],
73
+ "path": ["employee", "surname"]
74
+ },
75
+ {
76
+ "display": [
77
+ {
78
+ "description": "Phone Number",
79
+ "label": "Phone Number",
80
+ "lang": "en-US"
81
+ }
82
+ ],
83
+ "path": ["employee", "phoneNumber"]
84
+ },
85
+ {
86
+ "display": [
87
+ {
88
+ "description": "Phone number country code in E.164 format (e.g., +1, +44)",
89
+ "label": "Country Code",
90
+ "lang": "en-US"
91
+ }
92
+ ],
93
+ "path": ["employee", "phoneNumber", "countryCode"]
94
+ },
95
+ {
96
+ "display": [
97
+ {
98
+ "description": "The local portion of the phone number (area code + number)",
99
+ "label": "Local Number",
100
+ "lang": "en-US"
101
+ }
102
+ ],
103
+ "path": ["employee", "phoneNumber", "localNumber"]
104
+ },
105
+ {
106
+ "display": [
107
+ {
108
+ "description": "Employee ID",
109
+ "label": "Employee ID",
110
+ "lang": "en-US"
111
+ }
112
+ ],
113
+ "path": ["employee", "employeeID"]
114
+ },
115
+ {
116
+ "display": [
117
+ {
118
+ "description": "Email Address",
119
+ "label": "Email Address",
120
+ "lang": "en-US"
121
+ }
122
+ ],
123
+ "path": ["employee", "email"]
124
+ },
125
+ {
126
+ "display": [
127
+ {
128
+ "description": "Job Title",
129
+ "label": "Job Title",
130
+ "lang": "en-US"
131
+ }
132
+ ],
133
+ "path": ["employee", "jobTitle"]
134
+ },
135
+ {
136
+ "display": [
137
+ {
138
+ "description": "An array of Pseudo City Codes (PCCs) associated with the employee",
139
+ "label": "Pseudo City Codes (PCCs)",
140
+ "lang": "en-US"
141
+ }
142
+ ],
143
+ "path": ["employee", "pcc", null]
144
+ }
145
+ ]
146
+ }
@@ -0,0 +1 @@
1
+ <svg width="2072" height="1173" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" overflow="hidden"><g transform="translate(-430 -944)"><g><path d="M436.5 1003.59C436.5 972.61 461.611 947.5 492.586 947.5L2426.41 947.5C2457.39 947.5 2482.5 972.61 2482.5 1003.59L2482.5 2058.41C2482.5 2089.39 2457.39 2114.5 2426.41 2114.5L492.586 2114.5C461.611 2114.5 436.5 2089.39 436.5 2058.41Z" stroke="#060F6A" stroke-width="4.58333" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="8" stroke-opacity="1" fill="#1E32FA" fill-rule="evenodd" fill-opacity="1"/><g><g><g><path d="M167.265 98.1205C173.344 93.1858 178.95 86.5142 182.542 79.3491 177.608 77.7503 172.377 76.6449 167.265 76.6449L167.265 98.1008ZM163.495 97.9428C157.238 93.1858 151.671 86.5142 148.059 79.3491 152.974 77.5924 158.224 76.6449 163.495 76.6449L163.495 97.9231ZM167.265 2.07255C173.344 6.98746 178.95 13.5012 182.542 20.6663 177.608 22.4033 172.377 23.5284 167.265 23.5284L167.265 2.07255ZM163.495 2.07255C157.238 6.98746 151.671 13.6788 148.059 20.6663 152.974 22.2651 158.224 23.5284 163.495 23.5284L163.495 2.07255ZM167.265 72.8354 167.265 51.8138 190.083 51.8138C190.083 60.2422 187.951 68.5126 184.339 76.1515 179.088 74.2763 172.851 72.9735 167.265 72.8156ZM217.026 51.8138 194.03 51.8138C193.695 61.0514 191.721 69.3219 187.951 77.5726 192.866 79.8031 197.287 82.5073 201.551 86.001 210.926 76.8028 216.493 64.5452 217.006 51.8138ZM198.787 88.4091C195.175 85.3891 190.576 82.527 186.135 80.7703 182.029 88.2315 176.937 94.4491 170.541 99.9957 180.884 98.7324 190.576 94.9426 198.787 88.4091ZM163.495 72.8354 163.495 51.8138 140.539 51.8138C140.697 60.2422 142.631 68.6903 146.263 76.1515 151.671 74.2763 157.593 72.9735 163.495 72.8156ZM113.576 51.8138 136.571 51.8138C137.065 61.0514 139.039 69.1442 142.828 77.5726 137.716 79.8031 133.295 82.5073 129.031 86.001 119.655 76.8028 114.247 64.861 113.576 51.8138ZM131.795 88.4091C135.584 85.547 139.986 82.3691 144.447 80.7703 148.553 88.2315 153.645 94.4491 160.04 99.9957 149.678 98.7324 139.848 94.9426 131.795 88.4091ZM167.265 27.18 167.265 48.1819 190.083 48.1819C190.083 39.7338 187.951 31.6409 184.339 23.8442 178.93 25.7589 173.009 27.0221 167.265 27.18ZM217.026 48.1819 194.03 48.1819C193.695 39.1021 191.563 30.6935 187.951 22.5809 192.866 20.3505 197.445 17.4686 201.551 14.1328 211.42 23.6666 216.493 35.6084 217.006 48.1621ZM198.787 11.6063C194.997 14.8039 190.576 17.6266 186.135 19.403 182.029 11.7642 176.937 5.70445 170.541-3.50628e-15 180.884 1.28301 190.576 5.11229 198.787 11.6063ZM163.495 27.18 163.495 48.1819 140.539 48.1819C140.697 39.9114 142.631 31.483 146.263 23.8442 151.671 25.7589 157.593 27.0221 163.495 27.18ZM113.576 48.1819 136.571 48.1819C137.065 38.964 139.039 30.8514 142.828 22.5809 137.716 20.3505 133.295 17.6266 129.031 14.1328 119.478 23.3705 114.247 35.2926 113.576 48.1621ZM131.795 11.6063C135.584 14.8039 139.848 17.6266 144.447 19.403 148.375 11.9221 153.803 5.56628 160.04-3.50628e-15 149.678 1.28301 139.986 5.11229 131.795 11.6063ZM0 66.7954 103.233 66.7954C107.023 85.2312 120.149 100.529 146.263 111.168 143.282 119.892 133.137 128.005 122.596 128.005L66.6572 128.005C58.0906 128.005 51.3795 120.998 48.5964 115.431L105.542 115.431C108.996 114.819 109.174 112.115 105.7 111.799L49.7215 111.799C42.4972 111.799 35.9242 105.74 32.1542 99.2259L97.331 99.2259C100.608 98.7521 100.608 96.0479 97.331 95.5545L31.6607 95.5545C25.0877 95.5545 19.0477 88.0933 16.5607 83.0205L88.6262 83.0205C92.2384 82.527 92.2384 79.3491 88.6262 79.1912L15.2382 79.1912C9.49426 79.1912 3.92798 73.1512 0 66.7954ZM330.582 66.7954 227.349 66.7954C223.579 85.2312 210.433 100.529 184.339 111.168 187.28 119.892 197.445 128.005 207.966 128.005L263.944 128.005C272.491 128.005 279.202 120.998 281.985 115.431L225.04 115.431C221.605 114.819 221.408 112.115 224.882 111.799L280.86 111.799C288.085 111.799 294.638 105.74 298.408 99.2259L233.251 99.2259C229.954 98.7521 229.954 96.0479 233.251 95.5545L298.941 95.5545C305.494 95.5545 311.554 88.0933 314.001 83.0205L241.936 83.0205C238.343 82.527 238.343 79.3491 241.936 79.1912L315.324 79.1912C321.068 79.1912 326.654 73.1512 330.562 66.7954ZM214.223 206.387 247.344 140.874 269.017 140.874 282.637 206.387 262.128 206.387 261.161 198.59 239.468 198.59 236.034 206.387 214.223 206.387ZM244.916 184.951 258.852 184.951 255.24 160.948 244.897 184.951ZM171.193 206.387 178.733 157.119 159.547 157.119 162.843 140.558 221.783 140.558 218.486 157.119 200.268 157.119 192.885 206.387 171.212 206.387ZM82.5468 206.387 115.727 140.874 137.381 140.874 151.02 206.387 130.669 206.387 129.485 198.59 107.832 198.59 104.378 206.387 82.5468 206.387ZM113.26 184.951 127.215 184.951 123.583 160.948 113.26 184.951ZM47.0963 206.387 60.558 140.874 82.5468 140.874 69.1048 206.387 47.0963 206.387Z" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M407.483 0 410.03 0 410.03 206.762 407.483 206.762Z" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M708.497 84.2443 708.497 92.1397 706.72 92.1397 706.72 84.2443 704.134 84.2443 704.134 82.6454 711.122 82.6454 711.122 84.2443 708.497 84.2443" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M719.807 92.1397 719.985 84.343 717.932 92.1397 716.313 92.1397 714.26 84.343 714.438 92.1397 712.701 92.1397 712.701 82.6454 715.287 82.6454 717.142 89.6921 718.978 82.6454 721.544 82.6454 721.544 92.1397 719.807 92.1397" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M545.18 109.569 555.049 109.549 553.391 92.5542 545.18 109.569Z" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M615.785 109.569 625.713 109.569 623.976 92.4555 615.785 109.569Z" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/><path d="M687.672 85.1917 681.001 120.425 667.894 120.465 662.604 107.22C661.104 103.43 660.67 102.226 659.19 97.1336 658.795 100.608 658.696 101.476 658.084 104.97L655.124 120.504 643.813 120.504 651.057 82.1915 663.986 82.152 669.888 96.6401C671.27 100.588 671.645 101.733 672.809 106.036 673.204 102.285 673.283 101.456 673.994 97.1928L676.836 82.1322 687.08 82.1322C677.329 35.2334 635.799 0.0197386 586.019 0.0197386 585.585 0.0197386 585.15 0.0394772 584.716 0.0592157 601.672 14.2513 618.647 36.2795 632.543 63.8938 612.528 38.6087 590.539 16.6594 567.78 1.65804 561.819 2.72392 556.016 4.26353 550.45 6.31635 570.524 16.7186 592.513 35.2926 612.547 60.3211 587.874 39.7535 561.997 22.7388 536.83 12.4748 531.521 15.3566 526.507 18.7122 521.829 22.4625 544.055 28.5617 570.228 42.734 595.789 63.8938 567.386 48.5767 538.547 36.9112 511.821 31.6804 514.624 28.7196 517.625 25.9168 520.763 23.2915 497.629 42.2208 482.865 71.0194 482.865 103.272 482.865 135.525 496.721 162.33 518.572 181.24 516.203 179.147 513.894 176.976 511.723 174.686L511.742 174.686C538.488 169.475 567.346 157.81 595.77 142.453 570.188 163.653 543.995 177.825 521.75 183.904 526.448 187.655 531.442 191.01 536.751 193.892 561.938 183.648 587.795 166.613 612.528 146.026 592.473 171.094 570.445 189.668 550.371 200.09 555.917 202.143 561.701 203.702 567.642 204.768 590.44 189.767 612.449 167.817 632.503 142.473 618.587 170.147 601.573 192.214 584.598 206.406 585.091 206.406 585.565 206.446 586.039 206.446 642.925 206.446 689.192 160.297 689.192 103.292 689.192 97.1336 688.62 91.1133 687.594 85.2509ZM508.565 120.741 515.828 82.4086 528.047 82.3691 520.783 120.721 508.584 120.721ZM556.352 120.682 555.661 115.372 542.258 115.372 539.554 120.701 526.467 120.701 548.456 82.3691 562.313 82.3296 569.419 120.662 556.332 120.662ZM594.309 91.7449 588.822 120.642 576.682 120.642 582.15 91.7647 572.379 91.7647 574.195 82.2704 605.876 82.2309 604.08 91.7252 594.309 91.7252ZM626.937 120.721 626.266 115.411 612.844 115.411 610.159 120.741 597.072 120.741 619.061 82.4086 632.918 82.3691 640.024 120.701 626.937 120.701Z" fill="#FFFFFF" fill-rule="nonzero" fill-opacity="1" transform="matrix(1.00063 0 0 1 566 1051.12)"/></g></g></g><text fill="#FFFFFF" fill-opacity="1" font-family="25,25_MSFontService,sans-serif" font-style="normal" font-variant="normal" font-weight="400" font-stretch="normal" font-size="165" text-anchor="start" direction="ltr" writing-mode="lr-tb" unicode-bidi="normal" text-decoration="none" transform="matrix(1 0 0 1 1840.55 1208)">ID Card</text></g></g></svg>
@@ -0,0 +1,100 @@
1
+ import { defaultGenerateDigest } from '../defaultCallbacks'
2
+ import { createIntegrity, validateIntegrity } from '../index'
3
+
4
+ // type AgentType = IDIDManager & IKeyManager & IIdentifierResolution & IJwtService & IResolver & ISDJwtPlugin & ImDLMdoc
5
+ const fs = require('node:fs')
6
+
7
+ describe('VCT Integrity', () => {
8
+ const hasher = defaultGenerateDigest
9
+ it('create vct integrity values for boardingpass', async () => {
10
+ const boardingPassVCT: string = fs.readFileSync(__dirname + '/resources/BoardingPassCredential-vct.json', 'utf8')
11
+ const boardingPassVCTIntegrity = await createIntegrity({ input: boardingPassVCT, hasher, alg: 'sha256' })
12
+ // expect(boardingPassVCTIntegrity).toEqual('sha256-hV5MlMkg/KpZJU7haagwjgxnnsijmutXuf5QPeI6btU')
13
+ await validateIntegrity({ input: boardingPassVCT, integrityValue: boardingPassVCTIntegrity, hasher })
14
+
15
+ const boardingPassSchema: string = fs.readFileSync(__dirname + '/resources/boarding Pass VC Schema V1.0 sd-jwt.json', 'utf8')
16
+ const boardingPassSchemaIntegrity = await createIntegrity({ input: boardingPassSchema, hasher, alg: 'sha256' })
17
+ // expect(boardingPassSchemaIntegrity).toEqual('sha256-LCPRPfq0BCFVgW469g8F58ng0Nti1RL0+pir1hcQRa8')
18
+ await validateIntegrity({ input: boardingPassSchema, integrityValue: boardingPassSchemaIntegrity, hasher })
19
+
20
+ const boardingPassPNGLogo: string = fs.readFileSync(__dirname + '/resources/boardingpass-logo.png', 'utf8')
21
+ const boardingPassPNGLogoIntegrity = await createIntegrity({ input: boardingPassPNGLogo, hasher, alg: 'sha256' })
22
+ // expect(boardingPassPNGLogoIntegrity).toEqual('sha256-yu/K3O9TvEETXU58un2eMlfwWS4UnTryO9dOeIJihtM')
23
+ await validateIntegrity({ input: boardingPassPNGLogo, integrityValue: boardingPassPNGLogoIntegrity, hasher })
24
+
25
+ const boardingPassSVGLogo: string = fs.readFileSync(__dirname + '/resources/boardingpass.svg', 'utf8')
26
+ const boardingPassSVGLogoIntegrity = await createIntegrity({ input: boardingPassSVGLogo, hasher, alg: 'sha256' })
27
+ // expect(boardingPassSVGLogoIntegrity).toEqual('sha256-KC5EijLVECWtRRxGY78Z9wX2WQbFFzUKgb3pmVgOWmg')
28
+ await validateIntegrity({ input: boardingPassSVGLogo, integrityValue: boardingPassSVGLogoIntegrity, hasher })
29
+
30
+ console.log(
31
+ `boardingPass schema_uri#integrity: ${boardingPassSchemaIntegrity}\r\nboardingPass rendering simple uri#integrity: ${boardingPassPNGLogoIntegrity}\r\nboardingPass rendering svg uri#integrity: ${boardingPassSVGLogoIntegrity}\r\nboardingPass vct#integrity: ${boardingPassVCTIntegrity}`,
32
+ )
33
+ })
34
+
35
+ it('create vct integrity values for e-passport', async () => {
36
+ const ePassportVCT: string = fs.readFileSync(__dirname + '/resources/ePassportCredential-vct.json', 'utf8')
37
+ const ePassportVCTIntegrity = await createIntegrity({ input: ePassportVCT, hasher, alg: 'sha256' })
38
+ await validateIntegrity({ input: ePassportVCT, integrityValue: ePassportVCTIntegrity, hasher })
39
+
40
+ const ePassportSchema: string = fs.readFileSync(__dirname + '/resources/ePassport VC Schema V1.0.sd-jwt.json', 'utf8')
41
+ const ePassportSchemaIntegrity = await createIntegrity({ input: ePassportSchema, hasher, alg: 'sha256' })
42
+ await validateIntegrity({ input: ePassportSchema, integrityValue: ePassportSchemaIntegrity, hasher })
43
+
44
+ const ePassportPNGLogo: string = fs.readFileSync(__dirname + '/resources/epassport-logo.png', 'utf8')
45
+ const ePassportPNGLogoIntegrity = await createIntegrity({ input: ePassportPNGLogo, hasher, alg: 'sha256' })
46
+ await validateIntegrity({ input: ePassportPNGLogo, integrityValue: ePassportPNGLogoIntegrity, hasher })
47
+
48
+ const ePassportSVGLogo: string = fs.readFileSync(__dirname + '/resources/e-passport.svg', 'utf8')
49
+ const ePassportSVGLogoIntegrity = await createIntegrity({ input: ePassportSVGLogo, hasher, alg: 'sha256' })
50
+ await validateIntegrity({ input: ePassportSVGLogo, integrityValue: ePassportSVGLogoIntegrity, hasher })
51
+
52
+ console.log(
53
+ `ePassport schema_uri#integrity: ${ePassportSchemaIntegrity}\r\nePassport rendering simple uri#integrity: ${ePassportPNGLogoIntegrity}\r\nePassport rendering svg uri#integrity: ${ePassportSVGLogoIntegrity}\r\nePassport vct#integrity: ${ePassportVCTIntegrity}`,
54
+ )
55
+ })
56
+
57
+ it('create vct integrity values for loyalty prograam account', async () => {
58
+ const vct: string = fs.readFileSync(__dirname + '/resources/LoyaltyProgramAccountCredential-vct.json', 'utf8')
59
+ const vctIntegrity = await createIntegrity({ input: vct, hasher, alg: 'sha256' })
60
+ await validateIntegrity({ input: vct, integrityValue: vctIntegrity, hasher })
61
+
62
+ const schema: string = fs.readFileSync(__dirname + '/resources/LoyaltyProgram Account VC Schema V0.1 sd-jwt-schema.json', 'utf8')
63
+ const schemaIntegrity = await createIntegrity({ input: schema, hasher, alg: 'sha256' })
64
+ await validateIntegrity({ input: schema, integrityValue: schemaIntegrity, hasher })
65
+
66
+ const pngLogo: string = fs.readFileSync(__dirname + '/resources/loyaltyprogramaccount-icon.png', 'utf8')
67
+ const pngLogoIntegrity = await createIntegrity({ input: pngLogo, hasher, alg: 'sha256' })
68
+ await validateIntegrity({ input: pngLogo, integrityValue: pngLogoIntegrity, hasher })
69
+
70
+ const svgLogo: string = fs.readFileSync(__dirname + '/resources/loyaltyprogramaccount.svg', 'utf8')
71
+ const svgLogoIntegrity = await createIntegrity({ input: svgLogo, hasher, alg: 'sha256' })
72
+ await validateIntegrity({ input: svgLogo, integrityValue: svgLogoIntegrity, hasher })
73
+
74
+ console.log(
75
+ `Loyalty Program schema_uri#integrity: ${schemaIntegrity}\r\nLoyalty Program rendering simple uri#integrity: ${pngLogoIntegrity}\r\nLoyalty Program rendering svg uri#integrity: ${svgLogoIntegrity}\r\nLoyalty Program vct#integrity: ${vctIntegrity}`,
76
+ )
77
+ })
78
+
79
+ it('create vct integrity values for travel agency account', async () => {
80
+ const vct: string = fs.readFileSync(__dirname + '/resources/travel-agency-EmployeeAgencyCredential-vct.json', 'utf8')
81
+ const vctIntegrity = await createIntegrity({ input: vct, hasher, alg: 'sha256' })
82
+ await validateIntegrity({ input: vct, integrityValue: vctIntegrity, hasher })
83
+
84
+ const schema: string = fs.readFileSync(__dirname + '/resources/travel-agency VC Employee v0.1 sd-jwt-schema.json', 'utf8')
85
+ const schemaIntegrity = await createIntegrity({ input: schema, hasher, alg: 'sha256' })
86
+ await validateIntegrity({ input: schema, integrityValue: schemaIntegrity, hasher })
87
+
88
+ const pngLogo: string = fs.readFileSync(__dirname + '/resources/travel-agency-vc-employee-logo.png', 'utf8')
89
+ const pngLogoIntegrity = await createIntegrity({ input: pngLogo, hasher, alg: 'sha256' })
90
+ await validateIntegrity({ input: pngLogo, integrityValue: pngLogoIntegrity, hasher })
91
+
92
+ const svgLogo: string = fs.readFileSync(__dirname + '/resources/travel-agency-vc-employee.svg', 'utf8')
93
+ const svgLogoIntegrity = await createIntegrity({ input: svgLogo, hasher, alg: 'sha256' })
94
+ await validateIntegrity({ input: svgLogo, integrityValue: svgLogoIntegrity, hasher })
95
+
96
+ console.log(
97
+ `Employee Agency schema_uri#integrity: ${schemaIntegrity}\r\nEmployee Agency rendering simple uri#integrity: ${pngLogoIntegrity}\r\nEmployee Agency rendering svg uri#integrity: ${svgLogoIntegrity}\r\nEmployee Agency vct#integrity: ${vctIntegrity}`,
98
+ )
99
+ })
100
+ })
@@ -143,11 +143,11 @@ describe('Agent plugin', () => {
143
143
  })
144
144
  }, 5000)
145
145
 
146
-
147
-
148
- it('verify a funke sd-jwt', async () => {
146
+ // FIXME: Cert expired
147
+ xit('verify a funke sd-jwt', async () => {
149
148
  const signature = 'JAd5ZLl2_vXOwLBhyd6ceIMY9OlBasubHs5pa1gIJu2njs9VoIOMNiybFPvjuUm2IwmEcHFE_wJpvRaAwNcp6Q'
150
- const headerAndPayload = 'eyJ0eXAiOiJ2YytzZC1qd3QiLCJraWQiOiIwM2RmMDg3ZGVhZTc2ZjMxMDgzYTUzMDg3MDFkZDViODIzODc5YzMyYjYwNTM0YTk2Mjg2ZTE3M2EyODQ3NGU5NWYiLCJ4NWMiOlsiTUlJRFNEQ0NBdTZnQXdJQkFnSVNLOTB5Mm9vN2xPVGFDZ0lMWlBzSHBvSTFNQW9HQ0NxR1NNNDlCQU1DTUZveEN6QUpCZ05WQkFZVEFrNU1NU1F3SWdZRFZRUUtEQnRUY0dobGNtVnZiaUJKYm5SbGNtNWhkR2x2Ym1Gc0lFSXVWaTR4Q3pBSkJnTlZCQXNNQWtsVU1SZ3dGZ1lEVlFRRERBOWpZUzV6Y0dobGNtVnZiaTVqYjIwd0hoY05NalF4TVRJMk1UazBPVE15V2hjTk1qVXdNakkwTWpFME9UTXlXakNCampFTE1Ba0dBMVVFQmhNQ1Rrd3hGakFVQmdOVkJBZ01EVTV2YjNKa0xVaHZiR3hoYm1ReEVqQVFCZ05WQkFjTUNVRnRjM1JsY21SaGJURWtNQ0lHQTFVRUNnd2JVM0JvWlhKbGIyNGdTVzUwWlhKdVlYUnBiMjVoYkNCQ0xsWXVNUXN3Q1FZRFZRUUxEQUpKVkRFZ01CNEdBMVVFQXd3WFpuVnVhMlV1WkdWdGJ5NXpjR2hsY21WdmJpNWpiMjB3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRmQ0gzcTUyOHhDRHBUQ0hBZDFiZ2poNXd5dGdVMHFXS0c0WE9paEhUcFh5Rlc5YnVkbVd3T0Zpb1JPSWJTeDFtTjZFbjhFNTYwUWpsWnpSa25Jek96bzRJQlhUQ0NBVmt3SFFZRFZSME9CQllFRklkUHNRMzlDZnhPSlkxVDJxbGRkZzdHd3Y2bk1COEdBMVVkSXdRWU1CYUFGT2NIeWwyVlhQbklvUDdPNDJSRkhvQ3pMRExCTUdFR0NDc0dBUVVGQndFQkJGVXdVekJSQmdnckJnRUZCUWN3QW9aRmFIUjBjRG92TDJWMUxtTmxjblF1WlhwallTNXBieTlqWlhKMGN5OWtZV0V4WWpSaU5DMDROV1prTFRSaVlUUXRZamsyWWkwek16SmhaR1E0T1RsalpUa3VZMlZ5TUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjREFUQWlCZ05WSFJFRUd6QVpnaGRtZFc1clpTNWtaVzF2TG5Od2FHVnlaVzl1TG1OdmJUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd1lRWURWUjBmQkZvd1dEQldvRlNnVW9aUWFIUjBjRG92TDJWMUxtTnliQzVsZW1OaExtbHZMMk55YkM4eVkyUm1OMk0xWlMxaU9XTmtMVFF6TVRjdFltSTFOaTB6T0Raa01qUTBNemd3WlRJdlkyRnpjR2hsY21WdmJtTnZiUzVqY213d0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFMejBWKzg5RlZBSUVhbU5Fblh5L1RQMmJCSlI1eUU4aS8xbDRmaFNlR2RVQWlBazgvMWZ2bHFnZEQrRFM0OGJCWEswczBaZkFMZ2RBR08vak90dEErdExZZz09IiwiTUlJQ0NEQ0NBYTZnQXdJQkFnSVRBUE1ncXd0WXpXUEJYYW9iSGh4RzlpU3lkVEFLQmdncWhrak9QUVFEQWpCYU1Rc3dDUVlEVlFRR0V3Sk9UREVrTUNJR0ExVUVDZ3diVTNCb1pYSmxiMjRnU1c1MFpYSnVZWFJwYjI1aGJDQkNMbFl1TVFzd0NRWURWUVFMREFKSlZERVlNQllHQTFVRUF3d1BZMkV1YzNCb1pYSmxiMjR1WTI5dE1CNFhEVEkwTURjeU9ESXhNalkwT1ZvWERUTTBNRGN5T0RJeE1qWTBPVm93V2pFTE1Ba0dBMVVFQmhNQ1Rrd3hKREFpQmdOVkJBb01HMU53YUdWeVpXOXVJRWx1ZEdWeWJtRjBhVzl1WVd3Z1FpNVdMakVMTUFrR0ExVUVDd3dDU1ZReEdEQVdCZ05WQkFNTUQyTmhMbk53YUdWeVpXOXVMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkVpQTBLZUVTU05yT2NtQ0RnYThZc0JrVVRnb3daR3dxdkwybjkxSlVwQU1kUlN3dmxWRmRxZGlMWG5rMnBRcVQxdlpuREcwSSt4K2l6MkViZHNHMGFhalV6QlJNQjBHQTFVZERnUVdCQlRuQjhwZGxWejV5S0QrenVOa1JSNkFzeXd5d1RBT0JnTlZIUThCQWY4RUJBTUNBYVl3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJSEg3aWUxT0FBYmZmNTI2MnJ6WlZRYThKOXpFTkc4QVFsSEhGeWRNZGdhWEFpRUExSWI4Mm1oSElZRHppRTBERGJIRUFYT3M5OGFsKzdkcG84ZlBHVkdUZUtJPSJdLCJhbGciOiJFUzI1NiJ9.eyJhZ2VHcm91cCI6eyJfc2QiOlsiT01pWFpoV1FwaGdhdzdpSjVESHN5bmFNOUthTU9Vc3VQU0ZubGpySTFIOCJdfSwidmN0IjoiQWdlR3JvdXAiLCJleHAiOjE3NjQxOTYzNjgsImlzcyI6ImZ1bmtlLmRlbW8uc3BoZXJlb24uY29tIiwiaWF0IjoxNzMzMDkyMzY4LCJfc2RfYWxnIjoiU0hBLTI1NiJ9'
149
+ const headerAndPayload =
150
+ 'eyJ0eXAiOiJ2YytzZC1qd3QiLCJraWQiOiIwM2RmMDg3ZGVhZTc2ZjMxMDgzYTUzMDg3MDFkZDViODIzODc5YzMyYjYwNTM0YTk2Mjg2ZTE3M2EyODQ3NGU5NWYiLCJ4NWMiOlsiTUlJRFNEQ0NBdTZnQXdJQkFnSVNLOTB5Mm9vN2xPVGFDZ0lMWlBzSHBvSTFNQW9HQ0NxR1NNNDlCQU1DTUZveEN6QUpCZ05WQkFZVEFrNU1NU1F3SWdZRFZRUUtEQnRUY0dobGNtVnZiaUJKYm5SbGNtNWhkR2x2Ym1Gc0lFSXVWaTR4Q3pBSkJnTlZCQXNNQWtsVU1SZ3dGZ1lEVlFRRERBOWpZUzV6Y0dobGNtVnZiaTVqYjIwd0hoY05NalF4TVRJMk1UazBPVE15V2hjTk1qVXdNakkwTWpFME9UTXlXakNCampFTE1Ba0dBMVVFQmhNQ1Rrd3hGakFVQmdOVkJBZ01EVTV2YjNKa0xVaHZiR3hoYm1ReEVqQVFCZ05WQkFjTUNVRnRjM1JsY21SaGJURWtNQ0lHQTFVRUNnd2JVM0JvWlhKbGIyNGdTVzUwWlhKdVlYUnBiMjVoYkNCQ0xsWXVNUXN3Q1FZRFZRUUxEQUpKVkRFZ01CNEdBMVVFQXd3WFpuVnVhMlV1WkdWdGJ5NXpjR2hsY21WdmJpNWpiMjB3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVRmQ0gzcTUyOHhDRHBUQ0hBZDFiZ2poNXd5dGdVMHFXS0c0WE9paEhUcFh5Rlc5YnVkbVd3T0Zpb1JPSWJTeDFtTjZFbjhFNTYwUWpsWnpSa25Jek96bzRJQlhUQ0NBVmt3SFFZRFZSME9CQllFRklkUHNRMzlDZnhPSlkxVDJxbGRkZzdHd3Y2bk1COEdBMVVkSXdRWU1CYUFGT2NIeWwyVlhQbklvUDdPNDJSRkhvQ3pMRExCTUdFR0NDc0dBUVVGQndFQkJGVXdVekJSQmdnckJnRUZCUWN3QW9aRmFIUjBjRG92TDJWMUxtTmxjblF1WlhwallTNXBieTlqWlhKMGN5OWtZV0V4WWpSaU5DMDROV1prTFRSaVlUUXRZamsyWWkwek16SmhaR1E0T1RsalpUa3VZMlZ5TUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjREFUQWlCZ05WSFJFRUd6QVpnaGRtZFc1clpTNWtaVzF2TG5Od2FHVnlaVzl1TG1OdmJUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd1lRWURWUjBmQkZvd1dEQldvRlNnVW9aUWFIUjBjRG92TDJWMUxtTnliQzVsZW1OaExtbHZMMk55YkM4eVkyUm1OMk0xWlMxaU9XTmtMVFF6TVRjdFltSTFOaTB6T0Raa01qUTBNemd3WlRJdlkyRnpjR2hsY21WdmJtTnZiUzVqY213d0NnWUlLb1pJemowRUF3SURTQUF3UlFJaEFMejBWKzg5RlZBSUVhbU5Fblh5L1RQMmJCSlI1eUU4aS8xbDRmaFNlR2RVQWlBazgvMWZ2bHFnZEQrRFM0OGJCWEswczBaZkFMZ2RBR08vak90dEErdExZZz09IiwiTUlJQ0NEQ0NBYTZnQXdJQkFnSVRBUE1ncXd0WXpXUEJYYW9iSGh4RzlpU3lkVEFLQmdncWhrak9QUVFEQWpCYU1Rc3dDUVlEVlFRR0V3Sk9UREVrTUNJR0ExVUVDZ3diVTNCb1pYSmxiMjRnU1c1MFpYSnVZWFJwYjI1aGJDQkNMbFl1TVFzd0NRWURWUVFMREFKSlZERVlNQllHQTFVRUF3d1BZMkV1YzNCb1pYSmxiMjR1WTI5dE1CNFhEVEkwTURjeU9ESXhNalkwT1ZvWERUTTBNRGN5T0RJeE1qWTBPVm93V2pFTE1Ba0dBMVVFQmhNQ1Rrd3hKREFpQmdOVkJBb01HMU53YUdWeVpXOXVJRWx1ZEdWeWJtRjBhVzl1WVd3Z1FpNVdMakVMTUFrR0ExVUVDd3dDU1ZReEdEQVdCZ05WQkFNTUQyTmhMbk53YUdWeVpXOXVMbU52YlRCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkVpQTBLZUVTU05yT2NtQ0RnYThZc0JrVVRnb3daR3dxdkwybjkxSlVwQU1kUlN3dmxWRmRxZGlMWG5rMnBRcVQxdlpuREcwSSt4K2l6MkViZHNHMGFhalV6QlJNQjBHQTFVZERnUVdCQlRuQjhwZGxWejV5S0QrenVOa1JSNkFzeXd5d1RBT0JnTlZIUThCQWY4RUJBTUNBYVl3RHdZRFZSMGxCQWd3QmdZRVZSMGxBREFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJSEg3aWUxT0FBYmZmNTI2MnJ6WlZRYThKOXpFTkc4QVFsSEhGeWRNZGdhWEFpRUExSWI4Mm1oSElZRHppRTBERGJIRUFYT3M5OGFsKzdkcG84ZlBHVkdUZUtJPSJdLCJhbGciOiJFUzI1NiJ9.eyJhZ2VHcm91cCI6eyJfc2QiOlsiT01pWFpoV1FwaGdhdzdpSjVESHN5bmFNOUthTU9Vc3VQU0ZubGpySTFIOCJdfSwidmN0IjoiQWdlR3JvdXAiLCJleHAiOjE3NjQxOTYzNjgsImlzcyI6ImZ1bmtlLmRlbW8uc3BoZXJlb24uY29tIiwiaWF0IjoxNzMzMDkyMzY4LCJfc2RfYWxnIjoiU0hBLTI1NiJ9'
151
151
  const disclusure = '~WyJmNmU2OWUyYy1iM2ZkLTRiMzUtOWFlOS03NjgwMGY1YzZlZjQiLCJhZ2VPdmVyIiwxOF0~'
152
152
  const credential = `${headerAndPayload}.${signature}${disclusure}`
153
153
  console.log(credential)
@@ -1,19 +1,15 @@
1
1
  import { Jwt, SDJwt } from '@sd-jwt/core'
2
2
  import { SDJwtVcInstance, SdJwtVcPayload } from '@sd-jwt/sd-jwt-vc'
3
- import { DisclosureFrame, JwtPayload, KbVerifier, PresentationFrame, Signer, Verifier } from '@sd-jwt/types'
3
+ import { DisclosureFrame, Hasher, JwtPayload, KbVerifier, PresentationFrame, Signer, Verifier } from '@sd-jwt/types'
4
4
  import { calculateJwkThumbprint, signatureAlgorithmFromKey } from '@sphereon/ssi-sdk-ext.key-utils'
5
5
  import { X509CertificateChainValidationOpts } from '@sphereon/ssi-sdk-ext.x509-utils'
6
- import { JWK, SdJwtTypeMetadata } from '@sphereon/ssi-types'
6
+ import { HasherSync, JWK, SdJwtTypeMetadata } from '@sphereon/ssi-types'
7
7
  import { IAgentPlugin } from '@veramo/core'
8
8
  import { decodeBase64url } from '@veramo/utils'
9
9
  import Debug from 'debug'
10
10
  import { defaultGenerateDigest, defaultGenerateSalt, defaultVerifySignature } from './defaultCallbacks'
11
11
  import { funkeTestCA, sphereonCA } from './trustAnchors'
12
- import {
13
- assertValidTypeMetadata,
14
- fetchUrlWithErrorHandling,
15
- validateIntegrity
16
- } from './utils'
12
+ import { assertValidTypeMetadata, fetchUrlWithErrorHandling, validateIntegrity } from './utils'
17
13
  import {
18
14
  Claims,
19
15
  FetchSdJwtTypeMetadataFromVctUrlArgs,
@@ -32,7 +28,7 @@ import {
32
28
  SdJWTImplementation,
33
29
  SdJwtVerifySignature,
34
30
  SignKeyArgs,
35
- SignKeyResult
31
+ SignKeyResult,
36
32
  } from './types'
37
33
 
38
34
  const debug = Debug('@sphereon/ssi-sdk.sd-jwt')
@@ -115,7 +111,7 @@ export class SDJwtPlugin implements IAgentPlugin {
115
111
  hasher: this.registeredImplementations.hasher,
116
112
  saltGenerator: this.registeredImplementations.saltGenerator,
117
113
  signAlg: alg ?? 'ES256',
118
- hashAlg: 'SHA-256',
114
+ hashAlg: 'sha-256',
119
115
  })
120
116
 
121
117
  const credential = await sdjwt.issue(args.credentialPayload, args.disclosureFrame as DisclosureFrame<typeof args.credentialPayload>, {
@@ -206,7 +202,7 @@ export class SDJwtPlugin implements IAgentPlugin {
206
202
  const { alg, signer } = await this.getSignerForIdentifier({ identifier: holder }, context)
207
203
 
208
204
  const sdjwt = new SDJwtVcInstance({
209
- hasher: this.registeredImplementations.hasher,
205
+ hasher: this.registeredImplementations.hasher ?? defaultGenerateDigest,
210
206
  saltGenerator: this.registeredImplementations.saltGenerator,
211
207
  kbSigner: signer,
212
208
  kbSignAlg: alg ?? 'ES256',
@@ -225,7 +221,7 @@ export class SDJwtPlugin implements IAgentPlugin {
225
221
  async verifySdJwtVc(args: IVerifySdJwtVcArgs, context: IRequiredContext): Promise<IVerifySdJwtVcResult> {
226
222
  // callback
227
223
  const verifier: Verifier = async (data: string, signature: string) => this.verify(sdjwt, context, data, signature)
228
- const sdjwt = new SDJwtVcInstance({ verifier, hasher: this.registeredImplementations.hasher })
224
+ const sdjwt = new SDJwtVcInstance({ verifier, hasher: this.registeredImplementations.hasher ?? defaultGenerateDigest })
229
225
  const { header = {}, payload, kb } = await sdjwt.verify(args.credential)
230
226
 
231
227
  return { header, payload: payload as SdJwtVcPayload, kb }
@@ -255,7 +251,13 @@ export class SDJwtPlugin implements IAgentPlugin {
255
251
  * @param signature - The signature
256
252
  * @returns
257
253
  */
258
- async verify(sdjwt: SDJwtVcInstance, context: IRequiredContext, data: string, signature: string, opts?: {x5cValidation?: X509CertificateChainValidationOpts}): Promise<boolean> {
254
+ async verify(
255
+ sdjwt: SDJwtVcInstance,
256
+ context: IRequiredContext,
257
+ data: string,
258
+ signature: string,
259
+ opts?: { x5cValidation?: X509CertificateChainValidationOpts },
260
+ ): Promise<boolean> {
259
261
  const decodedVC = await sdjwt.decode(`${data}.${signature}`)
260
262
  const issuer: string = ((decodedVC.jwt as Jwt).payload as Record<string, unknown>).iss as string
261
263
  const header = (decodedVC.jwt as Jwt).header as Record<string, any>
@@ -271,7 +273,7 @@ export class SDJwtPlugin implements IAgentPlugin {
271
273
  chain: x5c,
272
274
  trustAnchors: Array.from(trustAnchors),
273
275
  // TODO: Defaults to allowing untrusted certs! Fine for now, not when wallets go mainstream
274
- opts: opts?.x5cValidation ?? {trustRootWhenNoAnchors: true, allowNoTrustAnchorsFound: true},
276
+ opts: opts?.x5cValidation ?? { trustRootWhenNoAnchors: true, allowNoTrustAnchorsFound: true },
275
277
  })
276
278
 
277
279
  if (certificateValidationResult.error || !certificateValidationResult?.certificateChain) {
@@ -346,17 +348,49 @@ export class SDJwtPlugin implements IAgentPlugin {
346
348
  * @returns
347
349
  */
348
350
  async fetchSdJwtTypeMetadataFromVctUrl(args: FetchSdJwtTypeMetadataFromVctUrlArgs, context: IRequiredContext): Promise<SdJwtTypeMetadata> {
349
- const {vct, opts} = args
351
+ const { vct, vctIntegrity, opts } = args
350
352
  const url = new URL(vct)
351
353
 
352
354
  const response = await fetchUrlWithErrorHandling(url.toString())
353
355
  const metadata: SdJwtTypeMetadata = await response.json()
354
356
  assertValidTypeMetadata(metadata, vct)
355
357
 
356
- if (opts?.integrity && opts.hasher) {
357
- if (!(await validateIntegrity(metadata, opts.integrity, opts.hasher))) {
358
- throw new Error(`Integrity check failed. vct: ${vct}`)
358
+ const validate = async (vct: string, input: unknown, integrityValue?: string, hasher?: Hasher | HasherSync) => {
359
+ if (hasher && integrityValue) {
360
+ const validation = await validateIntegrity({ integrityValue, input, hasher })
361
+ if (!validation) {
362
+ return Promise.reject(Error(`Integrity check failed for vct: ${vct}, extends: ${metadata.extends}, integrity: ${integrityValue}}`))
363
+ }
364
+ }
365
+ }
366
+
367
+ const hasher = (opts?.hasher ?? this.registeredImplementations.hasher ?? defaultGenerateDigest) as Hasher | HasherSync | undefined
368
+ if (hasher) {
369
+ if (vctIntegrity) {
370
+ await validate(vct, metadata, vctIntegrity, hasher)
371
+ const vctValidation = await validateIntegrity({ integrityValue: vctIntegrity, input: metadata, hasher })
372
+ if (!vctValidation) {
373
+ return Promise.reject(Error(`Integrity check failed for vct: ${vct}, integrity: ${vctIntegrity}`))
374
+ }
375
+ }
376
+
377
+ if (metadata['extends#integrity']) {
378
+ const extendsMetadata = await this.fetchSdJwtTypeMetadataFromVctUrl({ vct: metadata['extends#integrity'], opts }, context)
379
+ await validate(vct, extendsMetadata, metadata['extends#integrity'], hasher)
380
+ }
381
+
382
+ if (metadata['schema_uri#integrity']) {
383
+ const schemaResponse = await fetchUrlWithErrorHandling(metadata.schema_uri!)
384
+ const schema = await schemaResponse.json()
385
+ await validate(vct, schema, metadata['schema_uri#integrity'], hasher)
359
386
  }
387
+
388
+ metadata.display?.forEach((display) => {
389
+ const simpleLogoIntegrity = display.rendering?.simple?.logo?.['uri#integrity']
390
+ if (simpleLogoIntegrity) {
391
+ console.log('TODO: Logo integrity check')
392
+ }
393
+ })
360
394
  }
361
395
 
362
396
  return metadata
@@ -391,5 +425,4 @@ export class SDJwtPlugin implements IAgentPlugin {
391
425
  }
392
426
  return parts[2].split('#')[0]
393
427
  }
394
-
395
428
  }
@@ -1,12 +1,13 @@
1
- import { Hasher } from '@sd-jwt/types'
2
1
  import { digestMethodParams } from '@sphereon/ssi-sdk-ext.key-utils'
3
- import { JWK, Loggers } from '@sphereon/ssi-types'
2
+ import { HasherSync, JWK, Loggers } from '@sphereon/ssi-types'
4
3
  import { v4 } from 'uuid'
5
4
  import * as u8a from 'uint8arrays'
6
5
  import { IRequiredContext, SdJwtVerifySignature } from './types'
7
6
 
8
- export const defaultGenerateDigest: Hasher = (data: string, alg: string): Uint8Array => {
9
- return digestMethodParams(alg.includes('256') ? 'SHA-256' : 'SHA-512').hash(u8a.fromString(data, 'utf-8'))
7
+ export const defaultGenerateDigest: HasherSync = (data: string | ArrayBuffer, alg: string): Uint8Array => {
8
+ return digestMethodParams(alg.includes('256') ? 'SHA-256' : 'SHA-512').hash(
9
+ typeof data === 'string' ? u8a.fromString(data, 'utf-8') : new Uint8Array(data),
10
+ )
10
11
  }
11
12
 
12
13
  export const defaultGenerateSalt = (): string => {
package/src/types.ts CHANGED
@@ -5,7 +5,7 @@ import { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
5
5
  import { X509CertificateChainValidationOpts } from '@sphereon/ssi-sdk-ext.x509-utils'
6
6
  import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
7
7
  import { ImDLMdoc } from '@sphereon/ssi-sdk.mdl-mdoc'
8
- import { AsyncHasher, JoseSignatureAlgorithm, SdJwtTypeMetadata } from '@sphereon/ssi-types'
8
+ import { HasherSync, JoseSignatureAlgorithm, SdJwtTypeMetadata } from '@sphereon/ssi-types'
9
9
  import { DIDDocumentSection, IAgentContext, IDIDManager, IKeyManager, IPluginMethodMap, IResolver } from '@veramo/core'
10
10
 
11
11
  export const sdJwtPluginContextMethods: Array<string> = ['createSdJwtVc', 'createSdJwtPresentation', 'verifySdJwtVc', 'verifySdJwtPresentation']
@@ -233,7 +233,7 @@ export type IRequiredContext = IAgentContext<IDIDManager & IIdentifierResolution
233
233
  export type SdJwtVerifySignature = (data: string, signature: string, publicKey: JsonWebKey) => Promise<boolean>
234
234
  export interface SdJWTImplementation {
235
235
  saltGenerator?: SaltGenerator
236
- hasher?: Hasher
236
+ hasher?: HasherSync
237
237
  verifySignature?: SdJwtVerifySignature
238
238
  }
239
239
 
@@ -252,12 +252,12 @@ export interface Claims {
252
252
 
253
253
  export type FetchSdJwtTypeMetadataFromVctUrlArgs = {
254
254
  vct: string
255
+ vctIntegrity?: string
255
256
  opts?: FetchSdJwtTypeMetadataFromVctUrlOpts
256
257
  }
257
258
 
258
259
  export type FetchSdJwtTypeMetadataFromVctUrlOpts = {
259
- hasher?: AsyncHasher
260
- integrity?: string
260
+ hasher?: HasherSync | Hasher
261
261
  }
262
262
 
263
263
  export type GetSignerForIdentifierArgs = {
package/src/utils.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { AsyncHasher, SdJwtTypeMetadata } from '@sphereon/ssi-types'
1
+ import { SdJwtTypeMetadata } from '@sphereon/ssi-types'
2
2
  import * as u8a from 'uint8arrays'
3
+ import { HasherSync } from '@sd-jwt/types'
4
+ import { Hasher } from '@sd-jwt/types'
3
5
 
4
6
  // Helper function to fetch API with error handling
5
7
  export async function fetchUrlWithErrorHandling(url: string): Promise<Response> {
@@ -10,9 +12,51 @@ export async function fetchUrlWithErrorHandling(url: string): Promise<Response>
10
12
  return response
11
13
  }
12
14
 
13
- export async function validateIntegrity(input: any, integrityValue: string, hasher: AsyncHasher, alg?: string): Promise<boolean> {
14
- const hash = await hasher(input, alg ?? 'sha256')
15
- return u8a.toString(hash, 'utf-8') === integrityValue
15
+ export type IntegrityAlg = 'sha256' | 'sha384' | 'sha512'
16
+
17
+ function extractHashAlgFromIntegrity(integrityValue?: string): IntegrityAlg | undefined {
18
+ const val = integrityValue?.toLowerCase().trim().split('-')[0]
19
+ if (val === 'sha256' || val === 'sha384' || val === 'sha512') {
20
+ return val as IntegrityAlg
21
+ }
22
+ return undefined
23
+ }
24
+
25
+ export function extractHashFromIntegrity(integrityValue?: string): string | undefined {
26
+ return integrityValue?.toLowerCase().trim().split('-')[1]
27
+ }
28
+
29
+ export async function validateIntegrity({
30
+ input,
31
+ integrityValue,
32
+ hasher,
33
+ }: {
34
+ input: any
35
+ integrityValue?: string
36
+ hasher: HasherSync | Hasher
37
+ }): Promise<boolean> {
38
+ if (!integrityValue) {
39
+ return true
40
+ }
41
+ const alg = extractHashAlgFromIntegrity(integrityValue)
42
+ if (!alg) {
43
+ return false
44
+ }
45
+ const calculatedHash = await createIntegrity({ hasher, input, alg })
46
+ return calculatedHash == integrityValue
47
+ }
48
+
49
+ export async function createIntegrity({
50
+ input,
51
+ hasher,
52
+ alg = 'sha256',
53
+ }: {
54
+ input: any
55
+ hasher: HasherSync | Hasher
56
+ alg?: IntegrityAlg
57
+ }): Promise<string> {
58
+ const calculatedHash = await hasher(typeof input === 'string' ? input : JSON.stringify(input), alg)
59
+ return `${alg}-${u8a.toString(calculatedHash, 'base64')}`
16
60
  }
17
61
 
18
62
  export function assertValidTypeMetadata(metadata: SdJwtTypeMetadata, vct: string): void {