@sphereon/ssi-sdk.credential-vcdm2-jose-provider 0.33.1-feature.jose.vcdm.62 → 0.33.1-feature.jose.vcdm.63
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.
- package/README.md +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/agent/CredentialProviderVcdm2Jose.ts +1 -1
- package/src/did-jwt/JWT.ts +16 -37
- package/src/did-jwt/VerifierAlgorithm.ts +4 -24
- package/src/did-jwt/util.ts +6 -36
package/src/did-jwt/JWT.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { decodeBase64url, type EcdsaSignature, encodeBase64url, type KNOWN_JWA,
|
|
|
5
5
|
import VerifierAlgorithm from './VerifierAlgorithm'
|
|
6
6
|
import { JWT_ERROR } from 'did-jwt'
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
export type Signer = (data: string | Uint8Array) => Promise<EcdsaSignature | string>
|
|
10
9
|
export type SignerAlgorithm = (payload: string, signer: Signer) => Promise<string>
|
|
11
10
|
|
|
@@ -221,7 +220,7 @@ export async function createJWS(
|
|
|
221
220
|
payload: string | Partial<JWTPayload>,
|
|
222
221
|
signer: Signer,
|
|
223
222
|
header: Partial<JWTHeader> = {},
|
|
224
|
-
options: JWSCreationOptions = {}
|
|
223
|
+
options: JWSCreationOptions = {},
|
|
225
224
|
): Promise<string> {
|
|
226
225
|
if (!header.alg) header.alg = defaultAlg
|
|
227
226
|
const encodedPayload = typeof payload === 'string' ? payload : encodeSection(payload, options.canonicalize)
|
|
@@ -259,7 +258,7 @@ export async function createJWS(
|
|
|
259
258
|
export async function createJWT(
|
|
260
259
|
payload: Partial<JWTPayload>,
|
|
261
260
|
{ issuer, signer, alg, expiresIn, canonicalize }: JWTOptions,
|
|
262
|
-
header: Partial<JWTHeader> = {}
|
|
261
|
+
header: Partial<JWTHeader> = {},
|
|
263
262
|
): Promise<string> {
|
|
264
263
|
if (!signer) throw new Error('missing_signer: No Signer functionality has been configured')
|
|
265
264
|
if (!issuer) throw new Error('missing_issuer: No issuing DID has been configured')
|
|
@@ -305,7 +304,7 @@ export async function createJWT(
|
|
|
305
304
|
export async function createMultisignatureJWT(
|
|
306
305
|
payload: Partial<JWTPayload>,
|
|
307
306
|
{ expiresIn, canonicalize }: Partial<JWTOptions>,
|
|
308
|
-
issuers: { issuer: string; signer: Signer; alg: string }[]
|
|
307
|
+
issuers: { issuer: string; signer: Signer; alg: string }[],
|
|
309
308
|
): Promise<string> {
|
|
310
309
|
if (issuers.length === 0) throw new Error('invalid_argument: must provide one or more issuers')
|
|
311
310
|
|
|
@@ -337,7 +336,7 @@ export async function createMultisignatureJWT(
|
|
|
337
336
|
|
|
338
337
|
export function verifyJWTDecoded(
|
|
339
338
|
{ header, payload, data, signature }: JWTDecoded,
|
|
340
|
-
pubKeys: VerificationMethod | VerificationMethod[]
|
|
339
|
+
pubKeys: VerificationMethod | VerificationMethod[],
|
|
341
340
|
): VerificationMethod {
|
|
342
341
|
if (!Array.isArray(pubKeys)) pubKeys = [pubKeys]
|
|
343
342
|
|
|
@@ -365,10 +364,7 @@ export function verifyJWTDecoded(
|
|
|
365
364
|
throw new Error(`${JWT_ERROR.INVALID_SIGNATURE}: no matching public key found`)
|
|
366
365
|
}
|
|
367
366
|
|
|
368
|
-
export function verifyJWSDecoded(
|
|
369
|
-
{ header, data, signature }: JWSDecoded,
|
|
370
|
-
pubKeys: VerificationMethod | VerificationMethod[]
|
|
371
|
-
): VerificationMethod {
|
|
367
|
+
export function verifyJWSDecoded({ header, data, signature }: JWSDecoded, pubKeys: VerificationMethod | VerificationMethod[]): VerificationMethod {
|
|
372
368
|
if (!Array.isArray(pubKeys)) pubKeys = [pubKeys]
|
|
373
369
|
const signer: VerificationMethod = VerifierAlgorithm(header.alg)(data, signature, pubKeys)
|
|
374
370
|
return signer
|
|
@@ -429,10 +425,10 @@ export async function verifyJWT(
|
|
|
429
425
|
proofPurpose: undefined,
|
|
430
426
|
policies: {},
|
|
431
427
|
didAuthenticator: undefined,
|
|
432
|
-
}
|
|
428
|
+
},
|
|
433
429
|
): Promise<JWTVerified> {
|
|
434
430
|
if (!options.resolver) throw new Error('missing_resolver: No DID resolver has been configured')
|
|
435
|
-
const { payload, header/*, signature, data*/ }: JWTDecoded = decodeJWT(jwt, false)
|
|
431
|
+
const { payload, header /*, signature, data*/ }: JWTDecoded = decodeJWT(jwt, false)
|
|
436
432
|
const proofPurpose: ProofPurposeTypes | undefined = Object.prototype.hasOwnProperty.call(options, 'auth')
|
|
437
433
|
? options.auth
|
|
438
434
|
? 'authentication'
|
|
@@ -482,12 +478,7 @@ export async function verifyJWT(
|
|
|
482
478
|
if (options.didAuthenticator) {
|
|
483
479
|
;({ didResolutionResult, authenticators, issuer } = options.didAuthenticator)
|
|
484
480
|
} else {
|
|
485
|
-
;({ didResolutionResult, authenticators, issuer } = await resolveAuthenticator(
|
|
486
|
-
options.resolver,
|
|
487
|
-
header.alg,
|
|
488
|
-
didUrl,
|
|
489
|
-
proofPurpose
|
|
490
|
-
))
|
|
481
|
+
;({ didResolutionResult, authenticators, issuer } = await resolveAuthenticator(options.resolver, header.alg, didUrl, proofPurpose))
|
|
491
482
|
// Add to options object for recursive reference
|
|
492
483
|
options.didAuthenticator = { didResolutionResult, authenticators, issuer }
|
|
493
484
|
}
|
|
@@ -534,9 +525,7 @@ export async function verifyJWT(
|
|
|
534
525
|
}
|
|
535
526
|
if (options.policies?.aud !== false && payload.aud) {
|
|
536
527
|
if (!options.audience && !options.callbackUrl) {
|
|
537
|
-
throw new Error(
|
|
538
|
-
`${JWT_ERROR.INVALID_AUDIENCE}: JWT audience is required but your app address has not been configured`
|
|
539
|
-
)
|
|
528
|
+
throw new Error(`${JWT_ERROR.INVALID_AUDIENCE}: JWT audience is required but your app address has not been configured`)
|
|
540
529
|
}
|
|
541
530
|
const audArray = Array.isArray(payload.aud) ? payload.aud : [payload.aud]
|
|
542
531
|
const matchedAudience = audArray.find((item) => options.audience === item || options.callbackUrl === item)
|
|
@@ -549,7 +538,7 @@ export async function verifyJWT(
|
|
|
549
538
|
return { verified: true, payload, didResolutionResult, issuer, signer, jwt, policies: options.policies }
|
|
550
539
|
}
|
|
551
540
|
throw new Error(
|
|
552
|
-
`${JWT_ERROR.INVALID_SIGNATURE}: JWT not valid. issuer DID document does not contain a verificationMethod that matches the signature
|
|
541
|
+
`${JWT_ERROR.INVALID_SIGNATURE}: JWT not valid. issuer DID document does not contain a verificationMethod that matches the signature.`,
|
|
553
542
|
)
|
|
554
543
|
}
|
|
555
544
|
|
|
@@ -579,7 +568,7 @@ export async function resolveAuthenticator(
|
|
|
579
568
|
resolver: Resolvable,
|
|
580
569
|
alg: string,
|
|
581
570
|
issuer: string,
|
|
582
|
-
proofPurpose?: ProofPurposeTypes
|
|
571
|
+
proofPurpose?: ProofPurposeTypes,
|
|
583
572
|
): Promise<DIDAuthenticator> {
|
|
584
573
|
const types: string[] = SUPPORTED_PUBLIC_KEY_TYPES[alg as KNOWN_JWA]
|
|
585
574
|
if (!types || types.length === 0) {
|
|
@@ -601,9 +590,7 @@ export async function resolveAuthenticator(
|
|
|
601
590
|
|
|
602
591
|
if (didResult.didResolutionMetadata?.error || didResult.didDocument == null) {
|
|
603
592
|
const { error, message } = didResult.didResolutionMetadata
|
|
604
|
-
throw new Error(
|
|
605
|
-
`${JWT_ERROR.RESOLVER_ERROR}: Unable to resolve DID document for ${issuer}: ${error}, ${message || ''}`
|
|
606
|
-
)
|
|
593
|
+
throw new Error(`${JWT_ERROR.RESOLVER_ERROR}: Unable to resolve DID document for ${issuer}: ${error}, ${message || ''}`)
|
|
607
594
|
}
|
|
608
595
|
|
|
609
596
|
const getPublicKeyById = (verificationMethods: VerificationMethod[], pubid?: string): VerificationMethod | null => {
|
|
@@ -611,16 +598,10 @@ export async function resolveAuthenticator(
|
|
|
611
598
|
return filtered.length > 0 ? filtered[0] : null
|
|
612
599
|
}
|
|
613
600
|
|
|
614
|
-
let publicKeysToCheck: VerificationMethod[] = [
|
|
615
|
-
...(didResult?.didDocument?.verificationMethod || []),
|
|
616
|
-
...(didResult?.didDocument?.publicKey || []),
|
|
617
|
-
]
|
|
601
|
+
let publicKeysToCheck: VerificationMethod[] = [...(didResult?.didDocument?.verificationMethod || []), ...(didResult?.didDocument?.publicKey || [])]
|
|
618
602
|
if (typeof proofPurpose === 'string') {
|
|
619
603
|
// support legacy DID Documents that do not list assertionMethod
|
|
620
|
-
if (
|
|
621
|
-
proofPurpose.startsWith('assertion') &&
|
|
622
|
-
!Object.getOwnPropertyNames(didResult?.didDocument).includes('assertionMethod')
|
|
623
|
-
) {
|
|
604
|
+
if (proofPurpose.startsWith('assertion') && !Object.getOwnPropertyNames(didResult?.didDocument).includes('assertionMethod')) {
|
|
624
605
|
didResult.didDocument = { ...(<DIDDocument>didResult.didDocument) }
|
|
625
606
|
didResult.didDocument.assertionMethod = [...publicKeysToCheck.map((pk) => pk.id)]
|
|
626
607
|
}
|
|
@@ -639,13 +620,11 @@ export async function resolveAuthenticator(
|
|
|
639
620
|
.filter((key) => key != null) as VerificationMethod[]
|
|
640
621
|
}
|
|
641
622
|
|
|
642
|
-
const authenticators: VerificationMethod[] = publicKeysToCheck.filter(({ type }) =>
|
|
643
|
-
types.find((supported) => supported === type)
|
|
644
|
-
)
|
|
623
|
+
const authenticators: VerificationMethod[] = publicKeysToCheck.filter(({ type }) => types.find((supported) => supported === type))
|
|
645
624
|
|
|
646
625
|
if (typeof proofPurpose === 'string' && (!authenticators || authenticators.length === 0)) {
|
|
647
626
|
throw new Error(
|
|
648
|
-
`${JWT_ERROR.NO_SUITABLE_KEYS}: DID document for ${issuer} does not have public keys suitable for ${alg} with ${proofPurpose} purpose
|
|
627
|
+
`${JWT_ERROR.NO_SUITABLE_KEYS}: DID document for ${issuer} does not have public keys suitable for ${alg} with ${proofPurpose} purpose`,
|
|
649
628
|
)
|
|
650
629
|
}
|
|
651
630
|
if (!authenticators || authenticators.length === 0) {
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { toEthereumAddress } from 'did-jwt'
|
|
2
2
|
import type { VerificationMethod } from 'did-resolver'
|
|
3
|
-
import {
|
|
4
|
-
base64ToBytes,
|
|
5
|
-
bytesToHex,
|
|
6
|
-
type EcdsaSignature,
|
|
7
|
-
type ECDSASignature,
|
|
8
|
-
extractPublicKeyBytes,
|
|
9
|
-
type KNOWN_JWA,
|
|
10
|
-
stringToBytes,
|
|
11
|
-
} from './util'
|
|
3
|
+
import { base64ToBytes, bytesToHex, type EcdsaSignature, type ECDSASignature, extractPublicKeyBytes, type KNOWN_JWA, stringToBytes } from './util'
|
|
12
4
|
// @ts-ignore
|
|
13
5
|
// import { verifyBlockchainAccountId } from 'did-jwt'
|
|
14
6
|
import { secp256k1 } from '@noble/curves/secp256k1'
|
|
@@ -66,11 +58,7 @@ export function verifyES256(data: string, signature: string, authenticators: Ver
|
|
|
66
58
|
return signer
|
|
67
59
|
}
|
|
68
60
|
|
|
69
|
-
export function verifyES256K(
|
|
70
|
-
data: string,
|
|
71
|
-
signature: string,
|
|
72
|
-
authenticators: VerificationMethod[]
|
|
73
|
-
): VerificationMethod {
|
|
61
|
+
export function verifyES256K(data: string, signature: string, authenticators: VerificationMethod[]): VerificationMethod {
|
|
74
62
|
const hash = sha256(data)
|
|
75
63
|
const signatureNormalized = secp256k1.Signature.fromCompact(base64ToBytes(signature)).normalizeS()
|
|
76
64
|
const fullPublicKeys = authenticators.filter((a: VerificationMethod) => {
|
|
@@ -97,11 +85,7 @@ export function verifyES256K(
|
|
|
97
85
|
return signer
|
|
98
86
|
}
|
|
99
87
|
|
|
100
|
-
export function verifyRecoverableES256K(
|
|
101
|
-
data: string,
|
|
102
|
-
signature: string,
|
|
103
|
-
authenticators: VerificationMethod[]
|
|
104
|
-
): VerificationMethod {
|
|
88
|
+
export function verifyRecoverableES256K(data: string, signature: string, authenticators: VerificationMethod[]): VerificationMethod {
|
|
105
89
|
const signatures: ECDSASignature[] = []
|
|
106
90
|
if (signature.length > 86) {
|
|
107
91
|
signatures.push(toSignatureObject2(signature, true))
|
|
@@ -141,11 +125,7 @@ export function verifyRecoverableES256K(
|
|
|
141
125
|
throw new Error('invalid_signature: Signature invalid for JWT')
|
|
142
126
|
}
|
|
143
127
|
|
|
144
|
-
export function verifyEd25519(
|
|
145
|
-
data: string,
|
|
146
|
-
signature: string,
|
|
147
|
-
authenticators: VerificationMethod[]
|
|
148
|
-
): VerificationMethod {
|
|
128
|
+
export function verifyEd25519(data: string, signature: string, authenticators: VerificationMethod[]): VerificationMethod {
|
|
149
129
|
const clear = stringToBytes(data)
|
|
150
130
|
const signatureBytes = base64ToBytes(signature)
|
|
151
131
|
const signer = authenticators.find((a: VerificationMethod) => {
|
package/src/did-jwt/util.ts
CHANGED
|
@@ -12,8 +12,6 @@ import { p256 } from '@noble/curves/p256'
|
|
|
12
12
|
|
|
13
13
|
// const u8a = { toString, fromString, concat }
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
15
|
export interface EphemeralPublicKey {
|
|
18
16
|
kty?: string
|
|
19
17
|
//ECC
|
|
@@ -148,20 +146,8 @@ export const SUPPORTED_PUBLIC_KEY_TYPES: PublicKeyTypes = {
|
|
|
148
146
|
'JsonWebKey2020',
|
|
149
147
|
'Multikey',
|
|
150
148
|
],
|
|
151
|
-
Ed25519: [
|
|
152
|
-
|
|
153
|
-
'Ed25519VerificationKey2018',
|
|
154
|
-
'Ed25519VerificationKey2020',
|
|
155
|
-
'JsonWebKey2020',
|
|
156
|
-
'Multikey',
|
|
157
|
-
],
|
|
158
|
-
EdDSA: [
|
|
159
|
-
'ED25519SignatureVerification',
|
|
160
|
-
'Ed25519VerificationKey2018',
|
|
161
|
-
'Ed25519VerificationKey2020',
|
|
162
|
-
'JsonWebKey2020',
|
|
163
|
-
'Multikey',
|
|
164
|
-
],
|
|
149
|
+
Ed25519: ['ED25519SignatureVerification', 'Ed25519VerificationKey2018', 'Ed25519VerificationKey2020', 'JsonWebKey2020', 'Multikey'],
|
|
150
|
+
EdDSA: ['ED25519SignatureVerification', 'Ed25519VerificationKey2018', 'Ed25519VerificationKey2020', 'JsonWebKey2020', 'Multikey'],
|
|
165
151
|
}
|
|
166
152
|
|
|
167
153
|
export const VM_TO_KEY_TYPE: Record<KNOWN_VERIFICATION_METHOD, KNOWN_KEY_TYPE | undefined> = {
|
|
@@ -181,13 +167,7 @@ export const VM_TO_KEY_TYPE: Record<KNOWN_VERIFICATION_METHOD, KNOWN_KEY_TYPE |
|
|
|
181
167
|
Multikey: undefined, // key type must be extracted from the multicodec
|
|
182
168
|
}
|
|
183
169
|
|
|
184
|
-
export type KNOWN_CODECS =
|
|
185
|
-
| 'ed25519-pub'
|
|
186
|
-
| 'x25519-pub'
|
|
187
|
-
| 'secp256k1-pub'
|
|
188
|
-
| 'bls12_381-g1-pub'
|
|
189
|
-
| 'bls12_381-g2-pub'
|
|
190
|
-
| 'p256-pub'
|
|
170
|
+
export type KNOWN_CODECS = 'ed25519-pub' | 'x25519-pub' | 'secp256k1-pub' | 'bls12_381-g1-pub' | 'bls12_381-g2-pub' | 'p256-pub'
|
|
191
171
|
|
|
192
172
|
// this is from the multicodec table https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
193
173
|
export const supportedCodecs: Record<KNOWN_CODECS, number> = {
|
|
@@ -242,12 +222,7 @@ export function extractPublicKeyBytes(pk: VerificationMethod): { keyBytes: Uint8
|
|
|
242
222
|
}).toRawBytes(false),
|
|
243
223
|
keyType: 'P-256',
|
|
244
224
|
}
|
|
245
|
-
} else if (
|
|
246
|
-
pk.publicKeyJwk &&
|
|
247
|
-
pk.publicKeyJwk.kty === 'OKP' &&
|
|
248
|
-
['Ed25519', 'X25519'].includes(pk.publicKeyJwk.crv ?? '') &&
|
|
249
|
-
pk.publicKeyJwk.x
|
|
250
|
-
) {
|
|
225
|
+
} else if (pk.publicKeyJwk && pk.publicKeyJwk.kty === 'OKP' && ['Ed25519', 'X25519'].includes(pk.publicKeyJwk.crv ?? '') && pk.publicKeyJwk.x) {
|
|
251
226
|
return { keyBytes: base64ToBytes(pk.publicKeyJwk.x), keyType: pk.publicKeyJwk.crv as KNOWN_KEY_TYPE }
|
|
252
227
|
} else if (pk.publicKeyMultibase) {
|
|
253
228
|
const { keyBytes, keyType } = multibaseToBytes(pk.publicKeyMultibase)
|
|
@@ -268,11 +243,7 @@ export function extractPublicKeyBytes(pk: VerificationMethod): { keyBytes: Uint8
|
|
|
268
243
|
*
|
|
269
244
|
* @public
|
|
270
245
|
*/
|
|
271
|
-
export function bytesToMultibase(
|
|
272
|
-
b: Uint8Array,
|
|
273
|
-
base: BaseName = 'base58btc',
|
|
274
|
-
codec?: keyof typeof supportedCodecs | number
|
|
275
|
-
): string {
|
|
246
|
+
export function bytesToMultibase(b: Uint8Array, base: BaseName = 'base58btc', codec?: keyof typeof supportedCodecs | number): string {
|
|
276
247
|
if (!codec) {
|
|
277
248
|
return u8a.toString(encode(base, b), 'utf-8')
|
|
278
249
|
} else {
|
|
@@ -308,8 +279,7 @@ export function multibaseToBytes(s: string): { keyBytes: Uint8Array; keyType?: K
|
|
|
308
279
|
try {
|
|
309
280
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
310
281
|
const [codec, length] = varint.decode(bytes)
|
|
311
|
-
const possibleCodec: string | undefined =
|
|
312
|
-
Object.entries(supportedCodecs).filter(([, code]) => code === codec)?.[0][0] ?? ''
|
|
282
|
+
const possibleCodec: string | undefined = Object.entries(supportedCodecs).filter(([, code]) => code === codec)?.[0][0] ?? ''
|
|
313
283
|
return { keyBytes: bytes.slice(length), keyType: CODEC_TO_KEY_TYPE[possibleCodec as KNOWN_CODECS] }
|
|
314
284
|
} catch (e) {
|
|
315
285
|
// not a multicodec, return the bytes
|