@sphereon/ssi-sdk-ext.identifier-resolution 0.24.1-unstable.75 → 0.24.1-unstable.77
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 +380 -1
- package/dist/agent/IdentifierResolution.d.ts +9 -1
- package/dist/agent/IdentifierResolution.d.ts.map +1 -1
- package/dist/agent/IdentifierResolution.js +22 -3
- package/dist/agent/IdentifierResolution.js.map +1 -1
- package/dist/functions/externalIdentifierFunctions.d.ts +10 -0
- package/dist/functions/externalIdentifierFunctions.d.ts.map +1 -0
- package/dist/functions/externalIdentifierFunctions.js +167 -0
- package/dist/functions/externalIdentifierFunctions.js.map +1 -0
- package/dist/functions/index.d.ts +2 -12
- package/dist/functions/index.d.ts.map +1 -1
- package/dist/functions/index.js +15 -237
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/managedIdentifierFunctions.d.ts +12 -0
- package/dist/functions/managedIdentifierFunctions.d.ts.map +1 -0
- package/dist/functions/managedIdentifierFunctions.js +168 -0
- package/dist/functions/managedIdentifierFunctions.js.map +1 -0
- package/dist/types/IIdentifierResolution.d.ts +18 -159
- package/dist/types/IIdentifierResolution.d.ts.map +1 -1
- package/dist/types/IIdentifierResolution.js +0 -95
- package/dist/types/IIdentifierResolution.js.map +1 -1
- package/dist/types/common.d.ts +16 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +32 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/externalIdentifierTypes.d.ts +80 -0
- package/dist/types/externalIdentifierTypes.d.ts.map +1 -0
- package/dist/types/externalIdentifierTypes.js +35 -0
- package/dist/types/externalIdentifierTypes.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/managedIdentifierTypes.d.ts +81 -0
- package/dist/types/managedIdentifierTypes.d.ts.map +1 -0
- package/dist/types/managedIdentifierTypes.js +41 -0
- package/dist/types/managedIdentifierTypes.js.map +1 -0
- package/package.json +13 -11
- package/plugin.schema.json +1209 -222
- package/src/agent/IdentifierResolution.ts +31 -8
- package/src/functions/externalIdentifierFunctions.ts +183 -0
- package/src/functions/index.ts +2 -267
- package/src/functions/managedIdentifierFunctions.ts +178 -0
- package/src/types/IIdentifierResolution.ts +35 -278
- package/src/types/common.ts +37 -0
- package/src/types/externalIdentifierTypes.ts +119 -0
- package/src/types/index.ts +4 -0
- package/src/types/managedIdentifierTypes.ts +126 -0
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { IAgentContext, IAgentPlugin, IDIDManager, IKeyManager } from '@veramo/core'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { schema } from '..'
|
|
3
|
+
import { getManagedIdentifier, resolveExternalIdentifier } from '../functions'
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
ExternalIdentifierDidOpts,
|
|
6
|
+
ExternalIdentifierDidResult,
|
|
7
|
+
ExternalIdentifierOpts,
|
|
8
|
+
ExternalIdentifierResult,
|
|
9
|
+
ExternalIdentifierX5cOpts,
|
|
10
|
+
ExternalIdentifierX5cResult,
|
|
11
|
+
IIdentifierResolution,
|
|
6
12
|
ManagedIdentifierDidOpts,
|
|
7
13
|
ManagedIdentifierDidResult,
|
|
8
14
|
ManagedIdentifierJwkOpts,
|
|
@@ -10,11 +16,10 @@ import {
|
|
|
10
16
|
ManagedIdentifierKidOpts,
|
|
11
17
|
ManagedIdentifierKidResult,
|
|
12
18
|
ManagedIdentifierOpts,
|
|
19
|
+
ManagedIdentifierResult,
|
|
13
20
|
ManagedIdentifierX5cOpts,
|
|
14
21
|
ManagedIdentifierX5cResult,
|
|
15
|
-
|
|
16
|
-
} from '../index'
|
|
17
|
-
import { ExternalIdentifierOpts, IIdentifierResolution } from '../types/IIdentifierResolution'
|
|
22
|
+
} from '../types'
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
25
|
* @public
|
|
@@ -31,6 +36,10 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
31
36
|
identifierManagedGetByX5c: this.identifierGetManagedByX5c.bind(this),
|
|
32
37
|
|
|
33
38
|
identifierExternalResolve: this.identifierResolveExternal.bind(this),
|
|
39
|
+
identifierExternalResolveByDid: this.identifierExternalResolveByDid.bind(this),
|
|
40
|
+
identifierExternalResolveByX5c: this.identifierExternalResolveByX5c.bind(this),
|
|
41
|
+
|
|
42
|
+
// todo: JWKSet, oidc-discovery, oid4vci-issuer etc. Anything we already can resolve and need keys of
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
/**
|
|
@@ -40,6 +49,12 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
40
49
|
this._crypto = cryptoArg ?? global.crypto
|
|
41
50
|
}
|
|
42
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Main method for managed identifiers. We always go through this method (also the others) as we want to integrate a plugin for anomaly detection. Having a single method helps
|
|
54
|
+
* @param args
|
|
55
|
+
* @param context
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
43
58
|
private async identifierGetManaged(args: ManagedIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierResult> {
|
|
44
59
|
return await getManagedIdentifier({ ...args, crypto: this._crypto }, context)
|
|
45
60
|
}
|
|
@@ -63,7 +78,15 @@ export class IdentifierResolution implements IAgentPlugin {
|
|
|
63
78
|
return (await this.identifierGetManaged({ ...args, method: 'x5c' }, context)) as ManagedIdentifierX5cResult
|
|
64
79
|
}
|
|
65
80
|
|
|
66
|
-
private async identifierResolveExternal(args: ExternalIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<
|
|
67
|
-
return await
|
|
81
|
+
private async identifierResolveExternal(args: ExternalIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ExternalIdentifierResult> {
|
|
82
|
+
return await resolveExternalIdentifier({ ...args, crypto: this._crypto }, context)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async identifierExternalResolveByDid(args: ExternalIdentifierDidOpts, context: IAgentContext<any>): Promise<ExternalIdentifierDidResult> {
|
|
86
|
+
return (await this.identifierResolveExternal({ ...args, method: 'did' }, context)) as ExternalIdentifierDidResult
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async identifierExternalResolveByX5c(args: ExternalIdentifierX5cOpts, context: IAgentContext<any>): Promise<ExternalIdentifierX5cResult> {
|
|
90
|
+
return (await this.identifierResolveExternal({ ...args, method: 'x5c' }, context)) as ExternalIdentifierX5cResult
|
|
68
91
|
}
|
|
69
92
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { didDocumentToJwks, getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
2
|
+
import { calculateJwkThumbprint, JWK } from '@sphereon/ssi-sdk-ext.key-utils'
|
|
3
|
+
import {
|
|
4
|
+
getSubjectDN,
|
|
5
|
+
pemOrDerToX509Certificate,
|
|
6
|
+
PEMToDer,
|
|
7
|
+
validateX509CertificateChain,
|
|
8
|
+
X509ValidationResult,
|
|
9
|
+
} from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
10
|
+
import { contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
11
|
+
import { IParsedDID, parseDid } from '@sphereon/ssi-types'
|
|
12
|
+
import { IAgentContext, IDIDManager, IResolver } from '@veramo/core'
|
|
13
|
+
import { isDefined } from '@veramo/utils'
|
|
14
|
+
import { CryptoEngine, setEngine } from 'pkijs'
|
|
15
|
+
import {
|
|
16
|
+
ExternalIdentifierDidOpts,
|
|
17
|
+
ExternalIdentifierDidResult,
|
|
18
|
+
ExternalIdentifierMethod,
|
|
19
|
+
ExternalIdentifierOpts,
|
|
20
|
+
ExternalIdentifierResult,
|
|
21
|
+
ExternalIdentifierX5cOpts,
|
|
22
|
+
ExternalIdentifierX5cResult,
|
|
23
|
+
ExternalJwkInfo,
|
|
24
|
+
isExternalIdentifierDidOpts,
|
|
25
|
+
isExternalIdentifierJwksUrlOpts,
|
|
26
|
+
isExternalIdentifierKidOpts,
|
|
27
|
+
isExternalIdentifierOidcDiscoveryOpts,
|
|
28
|
+
isExternalIdentifierX5cOpts,
|
|
29
|
+
} from '../types'
|
|
30
|
+
|
|
31
|
+
export async function resolveExternalIdentifier(
|
|
32
|
+
opts: ExternalIdentifierOpts & {
|
|
33
|
+
crypto?: Crypto
|
|
34
|
+
},
|
|
35
|
+
context: IAgentContext<any>
|
|
36
|
+
): Promise<ExternalIdentifierResult> {
|
|
37
|
+
let method: ExternalIdentifierMethod | undefined
|
|
38
|
+
if (isExternalIdentifierDidOpts(opts)) {
|
|
39
|
+
return resolveExternalDidIdentifier(opts, context)
|
|
40
|
+
} else if (isExternalIdentifierX5cOpts(opts)) {
|
|
41
|
+
return resolveExternalX5cIdentifier(opts, context)
|
|
42
|
+
} else if (isExternalIdentifierKidOpts(opts)) {
|
|
43
|
+
method = 'kid'
|
|
44
|
+
} else if (isExternalIdentifierJwksUrlOpts(opts)) {
|
|
45
|
+
method = 'jwks-url'
|
|
46
|
+
} else if (isExternalIdentifierOidcDiscoveryOpts(opts)) {
|
|
47
|
+
method = 'oidc-discovery'
|
|
48
|
+
}
|
|
49
|
+
throw Error(`External resolution method ${method} is not yet implemented`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function resolveExternalX5cIdentifier(
|
|
53
|
+
opts: ExternalIdentifierX5cOpts & {
|
|
54
|
+
crypto?: Crypto
|
|
55
|
+
},
|
|
56
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
57
|
+
): Promise<ExternalIdentifierX5cResult> {
|
|
58
|
+
if (!isExternalIdentifierX5cOpts(opts)) {
|
|
59
|
+
return Promise.reject('External x5c Identifier args need to be provided')
|
|
60
|
+
}
|
|
61
|
+
const verify = opts.verify ?? true
|
|
62
|
+
const x5c = opts.identifier.map((derOrPem) => (derOrPem.includes('CERTIFICATE') ? PEMToDer(derOrPem) : derOrPem))
|
|
63
|
+
if (x5c.length === 0) {
|
|
64
|
+
return Promise.reject('Empty certification chain is now allowed')
|
|
65
|
+
}
|
|
66
|
+
const certificates = x5c.map(pemOrDerToX509Certificate)
|
|
67
|
+
|
|
68
|
+
let verificationResult: X509ValidationResult | undefined
|
|
69
|
+
let issuerJWK: JWK | undefined
|
|
70
|
+
let jwks: ExternalJwkInfo[] = []
|
|
71
|
+
|
|
72
|
+
if (verify) {
|
|
73
|
+
// We use the agent plugin if it is available as that is more powerful, but revert to the function otherwise
|
|
74
|
+
if (contextHasPlugin(context, 'verifyCertificateChain')) {
|
|
75
|
+
verificationResult = (await context.agent.verifyCertificateChain({
|
|
76
|
+
chain: opts.identifier,
|
|
77
|
+
trustAnchors: opts.trustAnchors ?? [],
|
|
78
|
+
verificationTime: opts.verificationTime,
|
|
79
|
+
})) as X509ValidationResult // We need to cast, as we know this is the value and we do not want to rely on the x509 plugin perse
|
|
80
|
+
} else {
|
|
81
|
+
verificationResult = await validateX509CertificateChain({
|
|
82
|
+
chain: opts.identifier,
|
|
83
|
+
trustAnchors: opts.trustAnchors ?? [],
|
|
84
|
+
verificationTime: opts.verificationTime,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
if (verificationResult.certificateChain) {
|
|
88
|
+
jwks = verificationResult.certificateChain.map((cert) => {
|
|
89
|
+
return {
|
|
90
|
+
jwk: cert.publicKeyJWK,
|
|
91
|
+
kid: cert.subject.dn.DN,
|
|
92
|
+
jwkThumbprint: calculateJwkThumbprint({ jwk: cert.publicKeyJWK }),
|
|
93
|
+
} satisfies ExternalJwkInfo
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!jwks || jwks.length === 0) {
|
|
98
|
+
const cryptoEngine = new CryptoEngine({
|
|
99
|
+
name: 'identifier_resolver_external',
|
|
100
|
+
crypto: opts.crypto ?? global.crypto,
|
|
101
|
+
})
|
|
102
|
+
setEngine(cryptoEngine.name, cryptoEngine)
|
|
103
|
+
jwks = await Promise.all(
|
|
104
|
+
certificates.map(async (cert) => {
|
|
105
|
+
const pk = await cert.getPublicKey(undefined, cryptoEngine)
|
|
106
|
+
const jwk = (await cryptoEngine.exportKey('jwk', pk)) as JWK
|
|
107
|
+
return {
|
|
108
|
+
jwk,
|
|
109
|
+
kid: getSubjectDN(cert).DN,
|
|
110
|
+
jwkThumbprint: calculateJwkThumbprint({ jwk }),
|
|
111
|
+
} satisfies ExternalJwkInfo
|
|
112
|
+
})
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
if (jwks.length === 0) {
|
|
116
|
+
return Promise.reject('Empty certification chain is now allowed')
|
|
117
|
+
}
|
|
118
|
+
if (!issuerJWK) {
|
|
119
|
+
issuerJWK = jwks[0].jwk
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
method: 'x5c',
|
|
124
|
+
verificationResult,
|
|
125
|
+
issuerJWK,
|
|
126
|
+
jwks,
|
|
127
|
+
certificates,
|
|
128
|
+
x5c,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function resolveExternalDidIdentifier(
|
|
133
|
+
opts: ExternalIdentifierDidOpts,
|
|
134
|
+
context: IAgentContext<IResolver & IDIDManager>
|
|
135
|
+
): Promise<ExternalIdentifierDidResult> {
|
|
136
|
+
if (!isExternalIdentifierDidOpts(opts)) {
|
|
137
|
+
return Promise.reject('External DID Identifier args need to be provided')
|
|
138
|
+
} else if (!contextHasPlugin<IResolver & IDIDManager>(context, 'resolveDid')) {
|
|
139
|
+
return Promise.reject(Error(`Cannot get external DID identifier if DID resolver plugin is not enabled!`))
|
|
140
|
+
}
|
|
141
|
+
const { uniresolverResolution = false, localResolution = true, resolverResolution = true } = opts
|
|
142
|
+
const did = opts.identifier
|
|
143
|
+
let parsed: IParsedDID
|
|
144
|
+
try {
|
|
145
|
+
parsed = parseDid(did)
|
|
146
|
+
} catch (error: unknown) {
|
|
147
|
+
// Error from did resolution spec
|
|
148
|
+
return Promise.reject(error)
|
|
149
|
+
}
|
|
150
|
+
const didParsed = parsed
|
|
151
|
+
const didResolutionResult = await getAgentResolver(context, {
|
|
152
|
+
uniresolverResolution,
|
|
153
|
+
localResolution,
|
|
154
|
+
resolverResolution,
|
|
155
|
+
}).resolve(did)
|
|
156
|
+
const didDocument = didResolutionResult.didDocument ?? undefined
|
|
157
|
+
const didJwks = didDocument ? didDocumentToJwks(didDocument) : undefined
|
|
158
|
+
const jwks = didJwks
|
|
159
|
+
? Array.from(
|
|
160
|
+
new Set(
|
|
161
|
+
Object.values(didJwks)
|
|
162
|
+
.filter((jwks) => isDefined(jwks) && jwks.length > 0)
|
|
163
|
+
.flatMap((jwks) => jwks)
|
|
164
|
+
)
|
|
165
|
+
).map((jwk) => {
|
|
166
|
+
return { jwk, jwkThumbprint: calculateJwkThumbprint({ jwk }), kid: jwk.kid }
|
|
167
|
+
})
|
|
168
|
+
: []
|
|
169
|
+
|
|
170
|
+
if (didResolutionResult?.didDocument) {
|
|
171
|
+
// @ts-ignore // Mandatory on the original object, but we already provide it directly
|
|
172
|
+
delete didResolutionResult['didDocument']
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
method: 'did',
|
|
176
|
+
did,
|
|
177
|
+
jwks,
|
|
178
|
+
didJwks,
|
|
179
|
+
didDocument,
|
|
180
|
+
didResolutionResult,
|
|
181
|
+
didParsed,
|
|
182
|
+
}
|
|
183
|
+
}
|
package/src/functions/index.ts
CHANGED
|
@@ -1,267 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { getSubjectDN, pemOrDerToX509Certificate, validateX509CertificateChain, X509ValidationResult } from '@sphereon/ssi-sdk-ext.x509-utils'
|
|
4
|
-
import { contextHasDidManager, contextHasKeyManager, contextHasPlugin } from '@sphereon/ssi-sdk.agent-config'
|
|
5
|
-
import { IParsedDID, parseDid } from '@sphereon/ssi-types'
|
|
6
|
-
import { IAgentContext, IDIDManager, IIdentifier, IKey, IKeyManager, IResolver } from '@veramo/core'
|
|
7
|
-
import { Certificate, CryptoEngine, setEngine } from 'pkijs'
|
|
8
|
-
import {
|
|
9
|
-
ExternalIdentifierDidOpts,
|
|
10
|
-
ExternalIdentifierDidResult,
|
|
11
|
-
ExternalIdentifierMethod,
|
|
12
|
-
ExternalIdentifierOpts,
|
|
13
|
-
ExternalIdentifierResult,
|
|
14
|
-
ExternalIdentifierX5cOpts,
|
|
15
|
-
ExternalIdentifierX5cResult,
|
|
16
|
-
ExternalJwkInfo,
|
|
17
|
-
isExternalIdentifierDidOpts,
|
|
18
|
-
isExternalIdentifierJwksUrlOpts,
|
|
19
|
-
isExternalIdentifierKidOpts,
|
|
20
|
-
isExternalIdentifierOidcDiscoveryOpts,
|
|
21
|
-
isExternalIdentifierX5cOpts,
|
|
22
|
-
isManagedIdentifierDidOpts,
|
|
23
|
-
isManagedIdentifierJwkOpts,
|
|
24
|
-
isManagedIdentifierKidOpts,
|
|
25
|
-
isManagedIdentifierX5cOpts,
|
|
26
|
-
ManagedIdentifierOpts,
|
|
27
|
-
ManagedIdentifierResult,
|
|
28
|
-
} from '../types/IIdentifierResolution'
|
|
29
|
-
|
|
30
|
-
export async function resolveExternalIdentifier(
|
|
31
|
-
opts: ExternalIdentifierOpts & {
|
|
32
|
-
crypto?: Crypto
|
|
33
|
-
},
|
|
34
|
-
context: IAgentContext<any>
|
|
35
|
-
): Promise<ExternalIdentifierResult> {
|
|
36
|
-
let method: ExternalIdentifierMethod | undefined
|
|
37
|
-
if (isExternalIdentifierDidOpts(opts)) {
|
|
38
|
-
return resolveExternalDidIdentifier(opts, context)
|
|
39
|
-
} else if (isExternalIdentifierX5cOpts(opts)) {
|
|
40
|
-
return resolveExternalX5cIdentifier(opts, context)
|
|
41
|
-
} else if (isExternalIdentifierKidOpts(opts)) {
|
|
42
|
-
method = 'kid'
|
|
43
|
-
} else if (isExternalIdentifierJwksUrlOpts(opts)) {
|
|
44
|
-
method = 'jwks-url'
|
|
45
|
-
} else if (isExternalIdentifierOidcDiscoveryOpts(opts)) {
|
|
46
|
-
method = 'oidc-discovery'
|
|
47
|
-
}
|
|
48
|
-
throw Error(`External resolution method ${method} is not yet implemented`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function resolveExternalX5cIdentifier(
|
|
52
|
-
opts: ExternalIdentifierX5cOpts & {
|
|
53
|
-
crypto?: Crypto
|
|
54
|
-
},
|
|
55
|
-
context: IAgentContext<IResolver & IDIDManager>
|
|
56
|
-
): Promise<ExternalIdentifierX5cResult> {
|
|
57
|
-
if (!isExternalIdentifierX5cOpts(opts)) {
|
|
58
|
-
return Promise.reject('External x5c Identifier args need to be provided')
|
|
59
|
-
}
|
|
60
|
-
const verify = opts.verify ?? true
|
|
61
|
-
const x5c = opts.identifier
|
|
62
|
-
if (x5c.length === 0) {
|
|
63
|
-
return Promise.reject('Empty certification chain is now allowed')
|
|
64
|
-
}
|
|
65
|
-
const certificates = x5c.map(pemOrDerToX509Certificate)
|
|
66
|
-
|
|
67
|
-
let verificationResult: X509ValidationResult | undefined
|
|
68
|
-
let issuerJWK: JWK | undefined
|
|
69
|
-
let jwks: ExternalJwkInfo[] = []
|
|
70
|
-
|
|
71
|
-
if (verify) {
|
|
72
|
-
// We use the agent plugin if it is available as that is more powerful, but revert to the function otherwise
|
|
73
|
-
if (contextHasPlugin(context, 'verifyCertificateChain')) {
|
|
74
|
-
verificationResult = (await context.agent.verifyCertificateChain({
|
|
75
|
-
chain: opts.identifier,
|
|
76
|
-
trustAnchors: opts.trustAnchors ?? [],
|
|
77
|
-
verificationTime: opts.verificationTime,
|
|
78
|
-
})) as X509ValidationResult // We need to cast, as we know this is the value and we do not want to rely on the x509 plugin perse
|
|
79
|
-
} else {
|
|
80
|
-
verificationResult = await validateX509CertificateChain({
|
|
81
|
-
chain: opts.identifier,
|
|
82
|
-
trustAnchors: opts.trustAnchors ?? [],
|
|
83
|
-
verificationTime: opts.verificationTime,
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
if (verificationResult.certificateChain) {
|
|
87
|
-
jwks = verificationResult.certificateChain.map((cert) => {
|
|
88
|
-
return {
|
|
89
|
-
jwk: cert.publicKeyJWK,
|
|
90
|
-
kid: cert.subject.dn.DN,
|
|
91
|
-
jwkThumbprint: calculateJwkThumbprint(cert.publicKeyJWK),
|
|
92
|
-
} satisfies ExternalJwkInfo
|
|
93
|
-
})
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (!jwks) {
|
|
97
|
-
const cryptoEngine = new CryptoEngine({
|
|
98
|
-
name: 'identifier_resolver_external',
|
|
99
|
-
crypto: opts.crypto ?? global.crypto,
|
|
100
|
-
})
|
|
101
|
-
setEngine(cryptoEngine.name, cryptoEngine)
|
|
102
|
-
jwks = await Promise.all(
|
|
103
|
-
certificates.map(async (cert) => {
|
|
104
|
-
const pk = await cert.getPublicKey(undefined, cryptoEngine)
|
|
105
|
-
const jwk = (await cryptoEngine.exportKey('jwk', pk)) as JWK
|
|
106
|
-
return {
|
|
107
|
-
jwk,
|
|
108
|
-
kid: getSubjectDN(cert).DN,
|
|
109
|
-
jwkThumbprint: calculateJwkThumbprint({ jwk }),
|
|
110
|
-
} satisfies ExternalJwkInfo
|
|
111
|
-
})
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
if (jwks.length === 0) {
|
|
115
|
-
return Promise.reject('Empty certification chain is now allowed')
|
|
116
|
-
}
|
|
117
|
-
if (!issuerJWK) {
|
|
118
|
-
issuerJWK = jwks[0].jwk
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
method: 'x5c',
|
|
123
|
-
verificationResult,
|
|
124
|
-
issuerJWK,
|
|
125
|
-
jwks,
|
|
126
|
-
certificates,
|
|
127
|
-
x5c,
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export async function resolveExternalDidIdentifier(
|
|
132
|
-
opts: ExternalIdentifierDidOpts,
|
|
133
|
-
context: IAgentContext<IResolver & IDIDManager>
|
|
134
|
-
): Promise<ExternalIdentifierDidResult> {
|
|
135
|
-
if (!isExternalIdentifierDidOpts(opts)) {
|
|
136
|
-
return Promise.reject('External DID Identifier args need to be provided')
|
|
137
|
-
} else if (!contextHasPlugin<IResolver & IDIDManager>(context, 'resolveDid')) {
|
|
138
|
-
return Promise.reject(Error(`Cannot get external DID identifier if DID resolver plugin is not enabled!`))
|
|
139
|
-
}
|
|
140
|
-
const { uniresolverResolution = false, localResolution = true, resolverResolution = true } = opts
|
|
141
|
-
const did = opts.identifier
|
|
142
|
-
let parsed: IParsedDID
|
|
143
|
-
try {
|
|
144
|
-
parsed = parseDid(did)
|
|
145
|
-
} catch (error: unknown) {
|
|
146
|
-
// Error from did resolution spec
|
|
147
|
-
return Promise.reject(error)
|
|
148
|
-
}
|
|
149
|
-
const didParsed = parsed
|
|
150
|
-
const didResolutionResult = await getAgentResolver(context, {
|
|
151
|
-
uniresolverResolution,
|
|
152
|
-
localResolution,
|
|
153
|
-
resolverResolution,
|
|
154
|
-
}).resolve(did)
|
|
155
|
-
const didDocument = didResolutionResult.didDocument ?? undefined
|
|
156
|
-
const didJwks = didDocument ? didDocumentToJwks(didDocument) : undefined
|
|
157
|
-
const jwks = didJwks
|
|
158
|
-
? Array.from(new Set(Object.values(didJwks).flatMap((jwks) => jwks))).map((jwk) => {
|
|
159
|
-
return { jwk, jwkThumbprint: calculateJwkThumbprint({ jwk }), kid: jwk.kid }
|
|
160
|
-
})
|
|
161
|
-
: []
|
|
162
|
-
|
|
163
|
-
if (didResolutionResult?.didDocument) {
|
|
164
|
-
// @ts-ignore // Mandatory on the original object, but we already provide it directly
|
|
165
|
-
delete didResolutionResult['didDocument']
|
|
166
|
-
}
|
|
167
|
-
return {
|
|
168
|
-
method: 'did',
|
|
169
|
-
did,
|
|
170
|
-
jwks,
|
|
171
|
-
didJwks,
|
|
172
|
-
didDocument,
|
|
173
|
-
didResolutionResult,
|
|
174
|
-
didParsed,
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export async function getManagedIdentifier(
|
|
179
|
-
opts: ManagedIdentifierOpts & {
|
|
180
|
-
crypto?: Crypto
|
|
181
|
-
},
|
|
182
|
-
context: IAgentContext<IKeyManager>
|
|
183
|
-
): Promise<ManagedIdentifierResult> {
|
|
184
|
-
let { method } = opts
|
|
185
|
-
let identifier: IIdentifier | undefined = undefined
|
|
186
|
-
let keys: IKey[] | undefined = undefined
|
|
187
|
-
let key: IKey | undefined = undefined
|
|
188
|
-
let certificate: Certificate | undefined = undefined
|
|
189
|
-
let jwk: JWK | undefined = undefined
|
|
190
|
-
let jwkThumbprint: string | undefined = undefined
|
|
191
|
-
let x5c: string[] | undefined
|
|
192
|
-
let controllerKeyId: string | undefined = undefined
|
|
193
|
-
let did: string | undefined = undefined
|
|
194
|
-
const cryptoImpl = opts.crypto ?? crypto
|
|
195
|
-
if (isManagedIdentifierKidOpts(opts)) {
|
|
196
|
-
method = 'kid'
|
|
197
|
-
if (!contextHasKeyManager(context)) {
|
|
198
|
-
return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
|
|
199
|
-
}
|
|
200
|
-
key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? opts.identifier })
|
|
201
|
-
} else if (isManagedIdentifierDidOpts(opts)) {
|
|
202
|
-
method = 'did'
|
|
203
|
-
if (!contextHasDidManager(context)) {
|
|
204
|
-
return Promise.reject(Error(`Cannot get DID identifier if DID Manager plugin is not enabled!`))
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (typeof opts.identifier === 'string') {
|
|
208
|
-
identifier = await context.agent.didManagerGet({ did: opts.identifier.split('#')[0] })
|
|
209
|
-
} else {
|
|
210
|
-
identifier = opts.identifier
|
|
211
|
-
}
|
|
212
|
-
if (identifier) {
|
|
213
|
-
did = identifier.did
|
|
214
|
-
keys = identifier?.keys // fixme: We really want to return the vmRelationship keys here actually
|
|
215
|
-
key = await getFirstKeyWithRelation(
|
|
216
|
-
{
|
|
217
|
-
...opts,
|
|
218
|
-
identifier,
|
|
219
|
-
vmRelationship: opts.vmRelationship ?? 'verificationMethod',
|
|
220
|
-
},
|
|
221
|
-
context
|
|
222
|
-
)
|
|
223
|
-
controllerKeyId = identifier.controllerKeyId
|
|
224
|
-
}
|
|
225
|
-
} else if (isManagedIdentifierJwkOpts(opts)) {
|
|
226
|
-
method = 'jwk'
|
|
227
|
-
if (!contextHasKeyManager(context)) {
|
|
228
|
-
return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
|
|
229
|
-
}
|
|
230
|
-
key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? calculateJwkThumbprint({ jwk: opts.identifier }) })
|
|
231
|
-
} else if (isManagedIdentifierX5cOpts(opts)) {
|
|
232
|
-
method = 'x5c'
|
|
233
|
-
x5c = opts.identifier
|
|
234
|
-
if (x5c.length === 0) {
|
|
235
|
-
return Promise.reject(`Cannot resolve x5c when an empty x5c is passed in`)
|
|
236
|
-
} else if (!contextHasKeyManager(context)) {
|
|
237
|
-
return Promise.reject(Error(`Cannot get X5c identifier if KeyManager plugin is not enabled!`))
|
|
238
|
-
}
|
|
239
|
-
certificate = pemOrDerToX509Certificate(x5c[0])
|
|
240
|
-
const cryptoEngine = new CryptoEngine({ name: 'identifier_resolver_managed', crypto: cryptoImpl })
|
|
241
|
-
setEngine(cryptoEngine.name, cryptoEngine)
|
|
242
|
-
const pk = await certificate.getPublicKey(undefined, cryptoEngine)
|
|
243
|
-
jwk = (await cryptoEngine.subtle.exportKey('jwk', pk)) as JWK
|
|
244
|
-
jwkThumbprint = calculateJwkThumbprint({ jwk })
|
|
245
|
-
key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? jwkThumbprint })
|
|
246
|
-
} else {
|
|
247
|
-
return Promise.reject(Error(`Could not determine identifier method. Please provide explicitly`))
|
|
248
|
-
}
|
|
249
|
-
if (!key || (isManagedIdentifierDidOpts(opts) && !identifier)) {
|
|
250
|
-
console.log(`Cannot find identifier`, opts.identifier)
|
|
251
|
-
return Promise.reject(`Cannot find identifier ${opts.identifier}`)
|
|
252
|
-
}
|
|
253
|
-
jwk = jwk ?? toJwk(key.publicKeyHex, key.type, { key })
|
|
254
|
-
const thumbprint = jwkThumbprint ?? key.meta?.jwkThumbprint ?? calculateJwkThumbprint({ jwk })
|
|
255
|
-
return {
|
|
256
|
-
method,
|
|
257
|
-
jwk,
|
|
258
|
-
jwkThumbprint: thumbprint,
|
|
259
|
-
...(identifier && { identifier }),
|
|
260
|
-
...(did && { did }),
|
|
261
|
-
...(controllerKeyId && { controllerKeyId }),
|
|
262
|
-
...(keys && { keys }),
|
|
263
|
-
...(certificate && { certificate: certificate.toJSON() }),
|
|
264
|
-
key,
|
|
265
|
-
kmsKeyRef: key.kid,
|
|
266
|
-
} as ManagedIdentifierResult
|
|
267
|
-
}
|
|
1
|
+
export * from './managedIdentifierFunctions'
|
|
2
|
+
export * from './externalIdentifierFunctions'
|