@sphereon/ssi-sdk-ext.identifier-resolution 0.24.1-unstable.93 → 0.25.1-feature.SDK.41.oidf.support.11
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/dist/agent/IdentifierResolution.d.ts +5 -0
- package/dist/agent/IdentifierResolution.d.ts.map +1 -1
- package/dist/agent/IdentifierResolution.js +31 -1
- package/dist/agent/IdentifierResolution.js.map +1 -1
- package/dist/functions/LegacySupport.d.ts +12 -0
- package/dist/functions/LegacySupport.d.ts.map +1 -0
- package/dist/functions/LegacySupport.js +39 -0
- package/dist/functions/LegacySupport.js.map +1 -0
- package/dist/functions/externalIdentifierFunctions.d.ts +17 -1
- package/dist/functions/externalIdentifierFunctions.d.ts.map +1 -1
- package/dist/functions/externalIdentifierFunctions.js +89 -6
- package/dist/functions/externalIdentifierFunctions.js.map +1 -1
- package/dist/functions/externalOIDFIdentifier.d.ts +19 -0
- package/dist/functions/externalOIDFIdentifier.d.ts.map +1 -0
- package/dist/functions/externalOIDFIdentifier.js +84 -0
- package/dist/functions/externalOIDFIdentifier.js.map +1 -0
- package/dist/functions/index.d.ts +2 -11
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +2 -36
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/managedIdentifierFunctions.d.ts +17 -3
- package/dist/functions/managedIdentifierFunctions.d.ts.map +1 -1
- package/dist/functions/managedIdentifierFunctions.js +134 -12
- package/dist/functions/managedIdentifierFunctions.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/types/IIdentifierResolution.d.ts +14 -3
- package/dist/types/IIdentifierResolution.d.ts.map +1 -1
- package/dist/types/IIdentifierResolution.js +18 -0
- package/dist/types/IIdentifierResolution.js.map +1 -1
- package/dist/types/common.d.ts +4 -1
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/common.js +21 -10
- package/dist/types/common.js.map +1 -1
- package/dist/types/externalIdentifierTypes.d.ts +38 -6
- package/dist/types/externalIdentifierTypes.d.ts.map +1 -1
- package/dist/types/externalIdentifierTypes.js +16 -7
- package/dist/types/externalIdentifierTypes.js.map +1 -1
- package/dist/types/managedIdentifierTypes.d.ts +43 -15
- package/dist/types/managedIdentifierTypes.d.ts.map +1 -1
- package/dist/types/managedIdentifierTypes.js +24 -11
- package/dist/types/managedIdentifierTypes.js.map +1 -1
- package/package.json +13 -12
- package/plugin.schema.json +2652 -281
- package/src/agent/IdentifierResolution.ts +71 -11
- package/src/functions/LegacySupport.ts +54 -0
- package/src/functions/externalIdentifierFunctions.ts +101 -6
- package/src/functions/externalOIDFIdentifier.ts +95 -0
- package/src/functions/index.ts +2 -51
- package/src/functions/managedIdentifierFunctions.ts +162 -14
- package/src/types/IIdentifierResolution.ts +47 -3
- package/src/types/IJwtService.d.ts +226 -0
- package/src/types/common.ts +14 -2
- package/src/types/externalIdentifierTypes.ts +76 -12
- package/src/types/managedIdentifierTypes.ts +78 -16
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IAgentContext, IAgentPlugin, IDIDManager, IKeyManager } from '@veramo/core'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ExternalIdentifierOIDFEntityIdOpts, ExternalIdentifierOIDFEntityIdResult, schema } from '..'
|
|
3
|
+
import { resolveExternalIdentifier, ensureManagedIdentifierResult } from '../functions'
|
|
4
4
|
import {
|
|
5
5
|
ExternalIdentifierDidOpts,
|
|
6
6
|
ExternalIdentifierDidResult,
|
|
@@ -8,18 +8,29 @@ import {
|
|
|
8
8
|
ExternalIdentifierResult,
|
|
9
9
|
ExternalIdentifierX5cOpts,
|
|
10
10
|
ExternalIdentifierX5cResult,
|
|
11
|
+
ExternalIdentifierCoseKeyOpts,
|
|
12
|
+
ExternalIdentifierCoseKeyResult,
|
|
13
|
+
ExternalIdentifierJwkOpts,
|
|
14
|
+
ExternalIdentifierJwkResult,
|
|
11
15
|
IIdentifierResolution,
|
|
16
|
+
ManagedIdentifierCoseKeyOpts,
|
|
17
|
+
ManagedIdentifierCoseKeyResult,
|
|
12
18
|
ManagedIdentifierDidOpts,
|
|
13
19
|
ManagedIdentifierDidResult,
|
|
14
20
|
ManagedIdentifierJwkOpts,
|
|
15
21
|
ManagedIdentifierJwkResult,
|
|
16
22
|
ManagedIdentifierKidOpts,
|
|
17
23
|
ManagedIdentifierKidResult,
|
|
18
|
-
ManagedIdentifierOpts,
|
|
19
24
|
ManagedIdentifierResult,
|
|
20
25
|
ManagedIdentifierX5cOpts,
|
|
21
26
|
ManagedIdentifierX5cResult,
|
|
27
|
+
ManagedIdentifierOID4VCIssuerResult,
|
|
28
|
+
ManagedIdentifierKeyOpts,
|
|
29
|
+
ManagedIdentifierKeyResult,
|
|
30
|
+
ManagedIdentifierOptsOrResult,
|
|
31
|
+
ManagedIdentifierOID4VCIssuerOpts
|
|
22
32
|
} from '../types'
|
|
33
|
+
import { IOIDFClient } from '@sphereon/ssi-sdk.oidf-client'
|
|
23
34
|
|
|
24
35
|
/**
|
|
25
36
|
* @public
|
|
@@ -35,10 +46,15 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
35
46
|
identifierManagedGetByJwk: this.identifierGetManagedByJwk.bind(this),
|
|
36
47
|
identifierManagedGetByX5c: this.identifierGetManagedByX5c.bind(this),
|
|
37
48
|
identifierManagedGetByKey: this.identifierGetManagedByKey.bind(this),
|
|
49
|
+
identifierManagedGetByCoseKey: this.identifierGetManagedByCoseKey.bind(this),
|
|
50
|
+
identifierManagedGetByOID4VCIssuer: this.identifierGetManagedByOID4VCIssuer.bind(this),
|
|
38
51
|
|
|
39
52
|
identifierExternalResolve: this.identifierResolveExternal.bind(this),
|
|
40
53
|
identifierExternalResolveByDid: this.identifierExternalResolveByDid.bind(this),
|
|
41
54
|
identifierExternalResolveByX5c: this.identifierExternalResolveByX5c.bind(this),
|
|
55
|
+
identifierExternalResolveByJwk: this.identifierExternalResolveByJwk.bind(this),
|
|
56
|
+
identifierExternalResolveByCoseKey: this.identifierExternalResolveByCoseKey.bind(this),
|
|
57
|
+
identifierExternalResolveByOIDFEntityId: this.identifierExternalResolveByOIDFEntityId.bind(this),
|
|
42
58
|
|
|
43
59
|
// todo: JWKSet, oidc-discovery, oid4vci-issuer etc. Anything we already can resolve and need keys of
|
|
44
60
|
}
|
|
@@ -57,34 +73,63 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
57
73
|
* @param context
|
|
58
74
|
* @private
|
|
59
75
|
*/
|
|
60
|
-
private async identifierGetManaged(
|
|
61
|
-
|
|
76
|
+
private async identifierGetManaged(
|
|
77
|
+
args: ManagedIdentifierOptsOrResult,
|
|
78
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
79
|
+
): Promise<ManagedIdentifierResult> {
|
|
80
|
+
return await ensureManagedIdentifierResult({ ...args, crypto: this._crypto }, context)
|
|
62
81
|
}
|
|
63
82
|
|
|
64
83
|
private async identifierGetManagedByDid(
|
|
65
84
|
args: ManagedIdentifierDidOpts,
|
|
66
|
-
context: IAgentContext<IKeyManager & IDIDManager>
|
|
85
|
+
context: IAgentContext<IKeyManager & IDIDManager & IIdentifierResolution>
|
|
67
86
|
): Promise<ManagedIdentifierDidResult> {
|
|
68
87
|
return (await this.identifierGetManaged({ ...args, method: 'did' }, context)) as ManagedIdentifierDidResult
|
|
69
88
|
}
|
|
70
89
|
|
|
71
|
-
private async identifierGetManagedByKid(
|
|
90
|
+
private async identifierGetManagedByKid(
|
|
91
|
+
args: ManagedIdentifierKidOpts,
|
|
92
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
93
|
+
): Promise<ManagedIdentifierKidResult> {
|
|
72
94
|
return (await this.identifierGetManaged({ ...args, method: 'kid' }, context)) as ManagedIdentifierKidResult
|
|
73
95
|
}
|
|
74
96
|
|
|
75
|
-
private async identifierGetManagedByKey(
|
|
97
|
+
private async identifierGetManagedByKey(
|
|
98
|
+
args: ManagedIdentifierKeyOpts,
|
|
99
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
100
|
+
): Promise<ManagedIdentifierKeyResult> {
|
|
76
101
|
return (await this.identifierGetManaged({ ...args, method: 'key' }, context)) as ManagedIdentifierKeyResult
|
|
77
102
|
}
|
|
78
103
|
|
|
79
|
-
private async
|
|
104
|
+
private async identifierGetManagedByCoseKey(
|
|
105
|
+
args: ManagedIdentifierCoseKeyOpts,
|
|
106
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
107
|
+
): Promise<ManagedIdentifierCoseKeyResult> {
|
|
108
|
+
return (await this.identifierGetManaged({ ...args, method: 'cose_key' }, context)) as ManagedIdentifierCoseKeyResult
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private async identifierGetManagedByOID4VCIssuer(
|
|
112
|
+
args: ManagedIdentifierOID4VCIssuerOpts,
|
|
113
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
114
|
+
): Promise<ManagedIdentifierOID4VCIssuerResult> {
|
|
115
|
+
return (await this.identifierGetManaged({ ...args, method: 'oid4vci-issuer' }, context)) as ManagedIdentifierOID4VCIssuerResult
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private async identifierGetManagedByJwk(
|
|
119
|
+
args: ManagedIdentifierJwkOpts,
|
|
120
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
121
|
+
): Promise<ManagedIdentifierJwkResult> {
|
|
80
122
|
return (await this.identifierGetManaged({ ...args, method: 'jwk' }, context)) as ManagedIdentifierJwkResult
|
|
81
123
|
}
|
|
82
124
|
|
|
83
|
-
private async identifierGetManagedByX5c(
|
|
125
|
+
private async identifierGetManagedByX5c(
|
|
126
|
+
args: ManagedIdentifierX5cOpts,
|
|
127
|
+
context: IAgentContext<IKeyManager & IIdentifierResolution>
|
|
128
|
+
): Promise<ManagedIdentifierX5cResult> {
|
|
84
129
|
return (await this.identifierGetManaged({ ...args, method: 'x5c' }, context)) as ManagedIdentifierX5cResult
|
|
85
130
|
}
|
|
86
131
|
|
|
87
|
-
private async identifierResolveExternal(args: ExternalIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ExternalIdentifierResult> {
|
|
132
|
+
private async identifierResolveExternal(args: ExternalIdentifierOpts, context: IAgentContext<IKeyManager | IOIDFClient>): Promise<ExternalIdentifierResult> {
|
|
88
133
|
return await resolveExternalIdentifier({ ...args, crypto: this._crypto }, context)
|
|
89
134
|
}
|
|
90
135
|
|
|
@@ -95,4 +140,19 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
95
140
|
private async identifierExternalResolveByX5c(args: ExternalIdentifierX5cOpts, context: IAgentContext<any>): Promise<ExternalIdentifierX5cResult> {
|
|
96
141
|
return (await this.identifierResolveExternal({ ...args, method: 'x5c' }, context)) as ExternalIdentifierX5cResult
|
|
97
142
|
}
|
|
143
|
+
|
|
144
|
+
private async identifierExternalResolveByCoseKey(
|
|
145
|
+
args: ExternalIdentifierCoseKeyOpts,
|
|
146
|
+
context: IAgentContext<any>
|
|
147
|
+
): Promise<ExternalIdentifierCoseKeyResult> {
|
|
148
|
+
return (await this.identifierResolveExternal({ ...args, method: 'cose_key' }, context)) as ExternalIdentifierCoseKeyResult
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private async identifierExternalResolveByJwk(args: ExternalIdentifierJwkOpts, context: IAgentContext<any>): Promise<ExternalIdentifierJwkResult> {
|
|
152
|
+
return (await this.identifierResolveExternal({ ...args, method: 'jwk' }, context)) as ExternalIdentifierJwkResult
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private async identifierExternalResolveByOIDFEntityId(args: ExternalIdentifierOIDFEntityIdOpts, context: IAgentContext<IOIDFClient>): Promise<ExternalIdentifierOIDFEntityIdResult> {
|
|
156
|
+
return (await this.identifierResolveExternal({ ...args, method: 'entity_id' }, context)) as ExternalIdentifierOIDFEntityIdResult
|
|
157
|
+
}
|
|
98
158
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { IIdentifier } from '@veramo/core'
|
|
2
|
+
import { ManagedIdentifierDidOpts, ManagedIdentifierOptsOrResult } from '../types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts legacy id opts key refs to the new ManagedIdentifierOpts
|
|
6
|
+
* @param opts
|
|
7
|
+
*/
|
|
8
|
+
export function legacyKeyRefsToIdentifierOpts(opts: {
|
|
9
|
+
idOpts?: ManagedIdentifierOptsOrResult
|
|
10
|
+
iss?: string
|
|
11
|
+
keyRef?: string
|
|
12
|
+
didOpts?: any
|
|
13
|
+
}): ManagedIdentifierOptsOrResult {
|
|
14
|
+
if (!opts.idOpts) {
|
|
15
|
+
console.warn(
|
|
16
|
+
`Legacy idOpts being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
17
|
+
)
|
|
18
|
+
// legacy way
|
|
19
|
+
let kmsKeyRef =
|
|
20
|
+
opts.keyRef ??
|
|
21
|
+
opts.didOpts?.idOpts?.kmsKeyRef ??
|
|
22
|
+
opts.didOpts?.kid ??
|
|
23
|
+
opts.didOpts.idOpts?.kid ??
|
|
24
|
+
(typeof opts.didOpts?.idOpts.identifier === 'object' ? (opts.didOpts?.idOpts.identifier as IIdentifier).keys[0].kid : undefined)
|
|
25
|
+
if (!kmsKeyRef) {
|
|
26
|
+
throw Error('Key ref is needed for access token signer')
|
|
27
|
+
}
|
|
28
|
+
let identifier = (opts.didOpts?.identifier ?? opts.didOpts?.idOpts?.identifier) as IIdentifier | undefined
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
kmsKeyRef: opts.keyRef ?? kmsKeyRef,
|
|
32
|
+
identifier: identifier ?? kmsKeyRef,
|
|
33
|
+
issuer: opts.iss,
|
|
34
|
+
} satisfies ManagedIdentifierDidOpts
|
|
35
|
+
} else {
|
|
36
|
+
const idOpts = opts.idOpts
|
|
37
|
+
if (opts.keyRef && !idOpts.kmsKeyRef) {
|
|
38
|
+
// legacy way
|
|
39
|
+
console.warn(
|
|
40
|
+
`Legacy keyRef being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
41
|
+
)
|
|
42
|
+
idOpts.kmsKeyRef = opts.keyRef
|
|
43
|
+
}
|
|
44
|
+
if (opts.iss && !idOpts.issuer) {
|
|
45
|
+
// legacy way
|
|
46
|
+
console.warn(
|
|
47
|
+
`Legacy iss being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
48
|
+
)
|
|
49
|
+
idOpts.issuer = opts.iss
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return idOpts
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { didDocumentToJwks, getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
2
|
-
import { calculateJwkThumbprint,
|
|
1
|
+
import { didDocumentToJwks, getAgentResolver, jwkTtoPublicKeyHex } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
2
|
+
import { calculateJwkThumbprint, coseKeyToJwk } from '@sphereon/ssi-sdk-ext.key-utils'
|
|
3
3
|
import {
|
|
4
4
|
getSubjectDN,
|
|
5
5
|
pemOrDerToX509Certificate,
|
|
@@ -8,25 +8,34 @@ import {
|
|
|
8
8
|
X509ValidationResult,
|
|
9
9
|
} from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
10
10
|
import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
11
|
-
import { IParsedDID, parseDid } from '@sphereon/ssi-types'
|
|
11
|
+
import { IParsedDID, JWK, parseDid } from '@sphereon/ssi-types'
|
|
12
12
|
import { IAgentContext, IDIDManager, IResolver } from '@veramo/core'
|
|
13
13
|
import { isDefined } from '@veramo/utils'
|
|
14
14
|
import { CryptoEngine, setEngine } from 'pkijs'
|
|
15
15
|
import {
|
|
16
|
+
ExternalIdentifierCoseKeyOpts,
|
|
17
|
+
ExternalIdentifierCoseKeyResult,
|
|
16
18
|
ExternalIdentifierDidOpts,
|
|
17
19
|
ExternalIdentifierDidResult,
|
|
20
|
+
ExternalIdentifierJwkOpts,
|
|
21
|
+
ExternalIdentifierJwkResult,
|
|
18
22
|
ExternalIdentifierMethod,
|
|
19
23
|
ExternalIdentifierOpts,
|
|
20
24
|
ExternalIdentifierResult,
|
|
21
25
|
ExternalIdentifierX5cOpts,
|
|
22
26
|
ExternalIdentifierX5cResult,
|
|
23
27
|
ExternalJwkInfo,
|
|
28
|
+
isExternalIdentifierCoseKeyOpts,
|
|
24
29
|
isExternalIdentifierDidOpts,
|
|
30
|
+
isExternalIdentifierJwkOpts,
|
|
25
31
|
isExternalIdentifierJwksUrlOpts,
|
|
26
32
|
isExternalIdentifierKidOpts,
|
|
27
33
|
isExternalIdentifierOidcDiscoveryOpts,
|
|
34
|
+
isExternalIdentifierOIDFEntityIdOpts,
|
|
28
35
|
isExternalIdentifierX5cOpts,
|
|
29
36
|
} from '../types'
|
|
37
|
+
import { resolveExternalOIDFEntityIdIdentifier } from '.'
|
|
38
|
+
|
|
30
39
|
|
|
31
40
|
export async function resolveExternalIdentifier(
|
|
32
41
|
opts: ExternalIdentifierOpts & {
|
|
@@ -39,13 +48,19 @@ export async function resolveExternalIdentifier(
|
|
|
39
48
|
return resolveExternalDidIdentifier(opts, context)
|
|
40
49
|
} else if (isExternalIdentifierX5cOpts(opts)) {
|
|
41
50
|
return resolveExternalX5cIdentifier(opts, context)
|
|
51
|
+
} else if (isExternalIdentifierJwkOpts(opts)) {
|
|
52
|
+
return resolveExternalJwkIdentifier(opts, context)
|
|
53
|
+
} else if (isExternalIdentifierCoseKeyOpts(opts)) {
|
|
54
|
+
return resolveExternalCoseKeyIdentifier(opts, context)
|
|
55
|
+
} else if (isExternalIdentifierOIDFEntityIdOpts(opts)) {
|
|
56
|
+
return resolveExternalOIDFEntityIdIdentifier(opts, context)
|
|
42
57
|
} else if (isExternalIdentifierKidOpts(opts)) {
|
|
43
58
|
method = 'kid'
|
|
44
59
|
} else if (isExternalIdentifierJwksUrlOpts(opts)) {
|
|
45
60
|
method = 'jwks-url'
|
|
46
61
|
} else if (isExternalIdentifierOidcDiscoveryOpts(opts)) {
|
|
47
62
|
method = 'oidc-discovery'
|
|
48
|
-
}
|
|
63
|
+
}
|
|
49
64
|
throw Error(`External resolution method ${method} is not yet implemented`)
|
|
50
65
|
}
|
|
51
66
|
|
|
@@ -61,7 +76,7 @@ export async function resolveExternalX5cIdentifier(
|
|
|
61
76
|
const verify = opts.verify ?? true
|
|
62
77
|
const x5c = opts.identifier.map((derOrPem) => (derOrPem.includes('CERTIFICATE') ? PEMToDer(derOrPem) : derOrPem))
|
|
63
78
|
if (x5c.length === 0) {
|
|
64
|
-
return Promise.reject('Empty certification chain is
|
|
79
|
+
return Promise.reject('Empty certification chain is not allowed')
|
|
65
80
|
}
|
|
66
81
|
const certificates = x5c.map(pemOrDerToX509Certificate)
|
|
67
82
|
|
|
@@ -82,6 +97,7 @@ export async function resolveExternalX5cIdentifier(
|
|
|
82
97
|
chain: opts.identifier,
|
|
83
98
|
trustAnchors: opts.trustAnchors ?? [],
|
|
84
99
|
verificationTime: opts.verificationTime,
|
|
100
|
+
opts,
|
|
85
101
|
})
|
|
86
102
|
}
|
|
87
103
|
if (verificationResult.certificateChain) {
|
|
@@ -90,6 +106,7 @@ export async function resolveExternalX5cIdentifier(
|
|
|
90
106
|
jwk: cert.publicKeyJWK,
|
|
91
107
|
kid: cert.subject.dn.DN,
|
|
92
108
|
jwkThumbprint: calculateJwkThumbprint({ jwk: cert.publicKeyJWK }),
|
|
109
|
+
publicKeyHex: jwkTtoPublicKeyHex(cert.publicKeyJWK),
|
|
93
110
|
} satisfies ExternalJwkInfo
|
|
94
111
|
})
|
|
95
112
|
}
|
|
@@ -108,6 +125,7 @@ export async function resolveExternalX5cIdentifier(
|
|
|
108
125
|
jwk,
|
|
109
126
|
kid: getSubjectDN(cert).DN,
|
|
110
127
|
jwkThumbprint: calculateJwkThumbprint({ jwk }),
|
|
128
|
+
publicKeyHex: jwkTtoPublicKeyHex(jwk),
|
|
111
129
|
} satisfies ExternalJwkInfo
|
|
112
130
|
})
|
|
113
131
|
)
|
|
@@ -129,6 +147,78 @@ export async function resolveExternalX5cIdentifier(
|
|
|
129
147
|
}
|
|
130
148
|
}
|
|
131
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Resolves a JWK. Normally this is just returning the JWK, but in case the JWK contains a x5c the chain is validated
|
|
152
|
+
* @param opts
|
|
153
|
+
* @param context
|
|
154
|
+
*/
|
|
155
|
+
export async function resolveExternalJwkIdentifier(
|
|
156
|
+
opts: ExternalIdentifierJwkOpts & {
|
|
157
|
+
x5c?: ExternalIdentifierX5cOpts
|
|
158
|
+
},
|
|
159
|
+
context: IAgentContext<any>
|
|
160
|
+
): Promise<ExternalIdentifierJwkResult> {
|
|
161
|
+
if (!isExternalIdentifierJwkOpts(opts)) {
|
|
162
|
+
return Promise.reject('External JWK Identifier args need to be provided')
|
|
163
|
+
}
|
|
164
|
+
const jwk = opts.identifier
|
|
165
|
+
let x5c: ExternalIdentifierX5cResult | undefined = undefined
|
|
166
|
+
if (jwk.x5c) {
|
|
167
|
+
x5c = await resolveExternalX5cIdentifier({ ...opts.x5c, identifier: jwk.x5c }, context)
|
|
168
|
+
}
|
|
169
|
+
const jwkThumbprint = calculateJwkThumbprint({ jwk })
|
|
170
|
+
return {
|
|
171
|
+
method: 'jwk',
|
|
172
|
+
jwk,
|
|
173
|
+
jwks: [
|
|
174
|
+
{
|
|
175
|
+
jwk,
|
|
176
|
+
jwkThumbprint,
|
|
177
|
+
kid: jwk.kid,
|
|
178
|
+
publicKeyHex: jwkTtoPublicKeyHex(jwk),
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
x5c,
|
|
182
|
+
} satisfies ExternalIdentifierJwkResult
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Resolves a JWK. Normally this is just returning the JWK, but in case the JWK contains a x5c the chain is validated
|
|
187
|
+
* @param opts
|
|
188
|
+
* @param context
|
|
189
|
+
*/
|
|
190
|
+
export async function resolveExternalCoseKeyIdentifier(
|
|
191
|
+
opts: ExternalIdentifierCoseKeyOpts & {
|
|
192
|
+
x5c?: ExternalIdentifierX5cOpts
|
|
193
|
+
},
|
|
194
|
+
context: IAgentContext<any>
|
|
195
|
+
): Promise<ExternalIdentifierCoseKeyResult> {
|
|
196
|
+
if (!isExternalIdentifierCoseKeyOpts(opts)) {
|
|
197
|
+
return Promise.reject('External Cose Key args need to be provided')
|
|
198
|
+
}
|
|
199
|
+
// TODO: We need to do cbor conversion here as well.
|
|
200
|
+
const coseKey = opts.identifier
|
|
201
|
+
let x5c: ExternalIdentifierX5cResult | undefined = undefined
|
|
202
|
+
if (coseKey.x5chain) {
|
|
203
|
+
x5c = await resolveExternalX5cIdentifier({ ...opts.x5c, identifier: coseKey.x5chain }, context)
|
|
204
|
+
}
|
|
205
|
+
const jwk = coseKeyToJwk(coseKey)
|
|
206
|
+
const jwkThumbprint = calculateJwkThumbprint({ jwk })
|
|
207
|
+
return {
|
|
208
|
+
method: 'cose_key',
|
|
209
|
+
coseKey,
|
|
210
|
+
jwks: [
|
|
211
|
+
{
|
|
212
|
+
jwk,
|
|
213
|
+
jwkThumbprint,
|
|
214
|
+
kid: coseKey.kid,
|
|
215
|
+
publicKeyHex: jwkTtoPublicKeyHex(jwk),
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
x5c,
|
|
219
|
+
} satisfies ExternalIdentifierCoseKeyResult
|
|
220
|
+
}
|
|
221
|
+
|
|
132
222
|
export async function resolveExternalDidIdentifier(
|
|
133
223
|
opts: ExternalIdentifierDidOpts,
|
|
134
224
|
context: IAgentContext<IResolver & IDIDManager>
|
|
@@ -163,7 +253,12 @@ export async function resolveExternalDidIdentifier(
|
|
|
163
253
|
.flatMap((jwks) => jwks)
|
|
164
254
|
)
|
|
165
255
|
).map((jwk) => {
|
|
166
|
-
return {
|
|
256
|
+
return {
|
|
257
|
+
jwk,
|
|
258
|
+
jwkThumbprint: calculateJwkThumbprint({ jwk }),
|
|
259
|
+
kid: jwk.kid,
|
|
260
|
+
publicKeyHex: jwkTtoPublicKeyHex(jwk),
|
|
261
|
+
}
|
|
167
262
|
})
|
|
168
263
|
: []
|
|
169
264
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ErrorMessage,
|
|
3
|
+
ExternalIdentifierOIDFEntityIdOpts,
|
|
4
|
+
ExternalIdentifierOIDFEntityIdResult, ExternalJwkInfo,
|
|
5
|
+
PublicKeyHex,
|
|
6
|
+
TrustedAnchor,
|
|
7
|
+
} from '../types'
|
|
8
|
+
import { IAgentContext } from '@veramo/core'
|
|
9
|
+
import { IOIDFClient } from '@sphereon/ssi-sdk.oidf-client'
|
|
10
|
+
import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
11
|
+
import { JWK } from '@sphereon/ssi-types'
|
|
12
|
+
import { IJwsValidationResult, VerifyJwsArgs } from '../types/IJwtService'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolves an OIDF Entity ID against multiple trust anchors to establish trusted relationships
|
|
16
|
+
*
|
|
17
|
+
* @param opts Configuration options containing the identifier to resolve and trust anchors to validate against
|
|
18
|
+
* @param context Agent context that must include the OIDF client plugin and JWT verification capabilities
|
|
19
|
+
*
|
|
20
|
+
* @returns Promise resolving to an ExternalIdentifierOIDFEntityIdResult containing:
|
|
21
|
+
* - trustedAnchors: Record mapping trust anchors to their public key hexes
|
|
22
|
+
* - errorList: Optional record of errors encountered per trust anchor
|
|
23
|
+
* - jwks: Array of JWK information from the trust chain
|
|
24
|
+
* - trustEstablished: Boolean indicating if any trust relationships were established
|
|
25
|
+
*
|
|
26
|
+
* @throws Error if trust anchors are missing or JWT verification plugin is not enabled
|
|
27
|
+
*/
|
|
28
|
+
export async function resolveExternalOIDFEntityIdIdentifier(
|
|
29
|
+
opts: ExternalIdentifierOIDFEntityIdOpts,
|
|
30
|
+
context: IAgentContext<IOIDFClient>
|
|
31
|
+
): Promise<ExternalIdentifierOIDFEntityIdResult> {
|
|
32
|
+
let { trustAnchors, identifier } = opts
|
|
33
|
+
|
|
34
|
+
if (!trustAnchors || trustAnchors.length === 0) {
|
|
35
|
+
return Promise.reject(Error('ExternalIdentifierOIDFEntityIdOpts is missing the trustAnchors'))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!contextHasPlugin(context, 'jwtVerifyJwsSignature')) {
|
|
39
|
+
return Promise.reject(Error('For OIDFEntityId resolving the agent needs to have the JwtService plugin enabled'))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const trustedAnchors: Record<TrustedAnchor, PublicKeyHex> = {}
|
|
43
|
+
const errorList: Record<TrustedAnchor, ErrorMessage> = {}
|
|
44
|
+
const jwkInfos: Array<ExternalJwkInfo> = []
|
|
45
|
+
|
|
46
|
+
for (const trustAnchor of trustAnchors) {
|
|
47
|
+
const resolveResult = await context.agent.resolveTrustChain({
|
|
48
|
+
entityIdentifier: identifier,
|
|
49
|
+
trustAnchors: [trustAnchor]
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
if (resolveResult.error || !resolveResult.trustChain) {
|
|
53
|
+
errorList[trustAnchor] = resolveResult.errorMessage ?? 'unspecified'
|
|
54
|
+
} else {
|
|
55
|
+
const trustChain: ReadonlyArray<string> = resolveResult.trustChain.asJsReadonlyArrayView()
|
|
56
|
+
let authorityJWK:JWK | undefined = undefined
|
|
57
|
+
for (const [i, jwt] of [...trustChain].reverse().entries()) {
|
|
58
|
+
const isLast = i === trustChain.length - 1
|
|
59
|
+
|
|
60
|
+
const verifyArgs:VerifyJwsArgs = {jws: jwt}
|
|
61
|
+
if(authorityJWK && !isLast) {
|
|
62
|
+
verifyArgs.jwk = authorityJWK
|
|
63
|
+
}
|
|
64
|
+
const jwtVerifyResult:IJwsValidationResult = await context.agent.jwtVerifyJwsSignature(verifyArgs)
|
|
65
|
+
if(jwtVerifyResult.error || jwtVerifyResult.critical) {
|
|
66
|
+
errorList[trustAnchor] = jwtVerifyResult.message
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
if(jwtVerifyResult.jws.signatures.length === 0) {
|
|
70
|
+
errorList[trustAnchor] = 'No signature was present in the trust anchor JWS'
|
|
71
|
+
break
|
|
72
|
+
}
|
|
73
|
+
const signature = jwtVerifyResult.jws.signatures[0]
|
|
74
|
+
if(signature.identifier.jwks.length === 0) {
|
|
75
|
+
errorList[trustAnchor] = 'No JWK was present in the trust anchor signature'
|
|
76
|
+
break
|
|
77
|
+
}
|
|
78
|
+
const jwkInfo:ExternalJwkInfo = signature.identifier.jwks[0]
|
|
79
|
+
if(!authorityJWK) {
|
|
80
|
+
authorityJWK = jwkInfo.jwk
|
|
81
|
+
jwkInfos.push(jwkInfo)
|
|
82
|
+
trustedAnchors[trustAnchor] = signature.publicKeyHex // When we have multiple hits from different trust anchor authorities the caller can infer which signature came from which trust anchor
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
method: 'entity_id',
|
|
90
|
+
trustedAnchors,
|
|
91
|
+
...(Object.keys(errorList).length > 0 && { errorList }),
|
|
92
|
+
jwks: jwkInfos,
|
|
93
|
+
trustEstablished: Object.keys(trustedAnchors).length > 0
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/functions/index.ts
CHANGED
|
@@ -1,53 +1,4 @@
|
|
|
1
|
-
import { IIdentifier } from '@veramo/core'
|
|
2
|
-
import { ManagedIdentifierDidOpts, ManagedIdentifierOpts } from '../types'
|
|
3
|
-
|
|
4
1
|
export * from './managedIdentifierFunctions'
|
|
5
2
|
export * from './externalIdentifierFunctions'
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* Converts legacy id opts key refs to the new ManagedIdentifierOpts
|
|
9
|
-
* @param opts
|
|
10
|
-
*/
|
|
11
|
-
export function legacyKeyRefsToIdentifierOpts(opts: {
|
|
12
|
-
idOpts?: ManagedIdentifierOpts
|
|
13
|
-
iss?: string
|
|
14
|
-
keyRef?: string
|
|
15
|
-
didOpts?: any
|
|
16
|
-
}): ManagedIdentifierOpts {
|
|
17
|
-
if (!opts.idOpts) {
|
|
18
|
-
console.warn(
|
|
19
|
-
`Legacy idOpts being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
20
|
-
)
|
|
21
|
-
// legacy way
|
|
22
|
-
let kmsKeyRef =
|
|
23
|
-
opts.keyRef ??
|
|
24
|
-
opts.didOpts?.idOpts?.kmsKeyRef ??
|
|
25
|
-
(typeof opts.didOpts?.idOpts.identifier === 'object' ? (opts.didOpts?.idOpts.identifier as IIdentifier).keys[0].kid : undefined)
|
|
26
|
-
if (!kmsKeyRef) {
|
|
27
|
-
throw Error('Key ref is needed for access token signer')
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
kmsKeyRef: opts.keyRef ?? kmsKeyRef,
|
|
31
|
-
identifier: kmsKeyRef,
|
|
32
|
-
issuer: opts.iss,
|
|
33
|
-
} satisfies ManagedIdentifierDidOpts
|
|
34
|
-
} else {
|
|
35
|
-
const idOpts = opts.idOpts
|
|
36
|
-
if (opts.keyRef && !idOpts.kmsKeyRef) {
|
|
37
|
-
// legacy way
|
|
38
|
-
console.warn(
|
|
39
|
-
`Legacy keyRef being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
40
|
-
)
|
|
41
|
-
idOpts.kmsKeyRef = opts.keyRef
|
|
42
|
-
}
|
|
43
|
-
if (opts.iss && !idOpts.issuer) {
|
|
44
|
-
// legacy way
|
|
45
|
-
console.warn(
|
|
46
|
-
`Legacy iss being used. Support will be dropped in the future. Consider switching to the idOpts, to have support for DIDs, JWKS, x5c etc. See https://github.com/Sphereon-Opensource/SSI-SDK-crypto-extensions/tree/feature/multi_identifier_support/packages/identifier-resolution`
|
|
47
|
-
)
|
|
48
|
-
idOpts.issuer = opts.iss
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return idOpts
|
|
52
|
-
}
|
|
53
|
-
}
|
|
3
|
+
export * from './externalOIDFIdentifier'
|
|
4
|
+
export * from './LegacySupport'
|