@sphereon/ssi-sdk-ext.identifier-resolution 0.24.1-next.84

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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +433 -0
  3. package/dist/agent/IdentifierResolution.d.ts +31 -0
  4. package/dist/agent/IdentifierResolution.d.ts.map +1 -0
  5. package/dist/agent/IdentifierResolution.js +86 -0
  6. package/dist/agent/IdentifierResolution.js.map +1 -0
  7. package/dist/functions/externalIdentifierFunctions.d.ts +10 -0
  8. package/dist/functions/externalIdentifierFunctions.d.ts.map +1 -0
  9. package/dist/functions/externalIdentifierFunctions.js +167 -0
  10. package/dist/functions/externalIdentifierFunctions.js.map +1 -0
  11. package/dist/functions/index.d.ts +14 -0
  12. package/dist/functions/index.d.ts.map +1 -0
  13. package/dist/functions/index.js +55 -0
  14. package/dist/functions/index.js.map +1 -0
  15. package/dist/functions/managedIdentifierFunctions.d.ts +12 -0
  16. package/dist/functions/managedIdentifierFunctions.d.ts.map +1 -0
  17. package/dist/functions/managedIdentifierFunctions.js +168 -0
  18. package/dist/functions/managedIdentifierFunctions.js.map +1 -0
  19. package/dist/index.d.ts +12 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +30 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/tsdoc-metadata.json +11 -0
  24. package/dist/types/IIdentifierResolution.d.ts +29 -0
  25. package/dist/types/IIdentifierResolution.d.ts.map +1 -0
  26. package/dist/types/IIdentifierResolution.js +3 -0
  27. package/dist/types/IIdentifierResolution.js.map +1 -0
  28. package/dist/types/common.d.ts +16 -0
  29. package/dist/types/common.d.ts.map +1 -0
  30. package/dist/types/common.js +32 -0
  31. package/dist/types/common.js.map +1 -0
  32. package/dist/types/externalIdentifierTypes.d.ts +80 -0
  33. package/dist/types/externalIdentifierTypes.d.ts.map +1 -0
  34. package/dist/types/externalIdentifierTypes.js +35 -0
  35. package/dist/types/externalIdentifierTypes.js.map +1 -0
  36. package/dist/types/index.d.ts +5 -0
  37. package/dist/types/index.d.ts.map +1 -0
  38. package/dist/types/index.js +21 -0
  39. package/dist/types/index.js.map +1 -0
  40. package/dist/types/managedIdentifierTypes.d.ts +81 -0
  41. package/dist/types/managedIdentifierTypes.d.ts.map +1 -0
  42. package/dist/types/managedIdentifierTypes.js +41 -0
  43. package/dist/types/managedIdentifierTypes.js.map +1 -0
  44. package/package.json +68 -0
  45. package/plugin.schema.json +1792 -0
  46. package/src/agent/IdentifierResolution.ts +92 -0
  47. package/src/functions/externalIdentifierFunctions.ts +183 -0
  48. package/src/functions/index.ts +53 -0
  49. package/src/functions/managedIdentifierFunctions.ts +178 -0
  50. package/src/index.ts +11 -0
  51. package/src/types/IIdentifierResolution.ts +54 -0
  52. package/src/types/common.ts +37 -0
  53. package/src/types/externalIdentifierTypes.ts +119 -0
  54. package/src/types/index.ts +4 -0
  55. package/src/types/managedIdentifierTypes.ts +126 -0
@@ -0,0 +1,92 @@
1
+ import { IAgentContext, IAgentPlugin, IDIDManager, IKeyManager } from '@veramo/core'
2
+ import { schema } from '..'
3
+ import { getManagedIdentifier, resolveExternalIdentifier } from '../functions'
4
+ import {
5
+ ExternalIdentifierDidOpts,
6
+ ExternalIdentifierDidResult,
7
+ ExternalIdentifierOpts,
8
+ ExternalIdentifierResult,
9
+ ExternalIdentifierX5cOpts,
10
+ ExternalIdentifierX5cResult,
11
+ IIdentifierResolution,
12
+ ManagedIdentifierDidOpts,
13
+ ManagedIdentifierDidResult,
14
+ ManagedIdentifierJwkOpts,
15
+ ManagedIdentifierJwkResult,
16
+ ManagedIdentifierKidOpts,
17
+ ManagedIdentifierKidResult,
18
+ ManagedIdentifierOpts,
19
+ ManagedIdentifierResult,
20
+ ManagedIdentifierX5cOpts,
21
+ ManagedIdentifierX5cResult,
22
+ } from '../types'
23
+
24
+ /**
25
+ * @public
26
+ */
27
+ export class IdentifierResolution implements IAgentPlugin {
28
+ private readonly _crypto: Crypto
29
+
30
+ readonly schema = schema.IMnemonicInfoGenerator
31
+ readonly methods: IIdentifierResolution = {
32
+ identifierManagedGet: this.identifierGetManaged.bind(this),
33
+ identifierManagedGetByDid: this.identifierGetManagedByDid.bind(this),
34
+ identifierManagedGetByKid: this.identifierGetManagedByKid.bind(this),
35
+ identifierManagedGetByJwk: this.identifierGetManagedByJwk.bind(this),
36
+ identifierManagedGetByX5c: this.identifierGetManagedByX5c.bind(this),
37
+
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
43
+ }
44
+
45
+ /**
46
+ * TODO: Add a cache, as we are retrieving the same keys/info quite often
47
+ */
48
+ constructor(opts?: { crypto?: Crypto }) {
49
+ this._crypto = opts?.crypto ?? global.crypto
50
+ }
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
+ */
58
+ private async identifierGetManaged(args: ManagedIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierResult> {
59
+ return await getManagedIdentifier({ ...args, crypto: this._crypto }, context)
60
+ }
61
+
62
+ private async identifierGetManagedByDid(
63
+ args: ManagedIdentifierDidOpts,
64
+ context: IAgentContext<IKeyManager & IDIDManager>
65
+ ): Promise<ManagedIdentifierDidResult> {
66
+ return (await this.identifierGetManaged({ ...args, method: 'did' }, context)) as ManagedIdentifierDidResult
67
+ }
68
+
69
+ private async identifierGetManagedByKid(args: ManagedIdentifierKidOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierKidResult> {
70
+ return (await this.identifierGetManaged({ ...args, method: 'kid' }, context)) as ManagedIdentifierKidResult
71
+ }
72
+
73
+ private async identifierGetManagedByJwk(args: ManagedIdentifierJwkOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierJwkResult> {
74
+ return (await this.identifierGetManaged({ ...args, method: 'jwk' }, context)) as ManagedIdentifierJwkResult
75
+ }
76
+
77
+ private async identifierGetManagedByX5c(args: ManagedIdentifierX5cOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierX5cResult> {
78
+ return (await this.identifierGetManaged({ ...args, method: 'x5c' }, context)) as ManagedIdentifierX5cResult
79
+ }
80
+
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
91
+ }
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
+ }
@@ -0,0 +1,53 @@
1
+ import { IIdentifier } from '@veramo/core'
2
+ import { ManagedIdentifierDidOpts, ManagedIdentifierOpts } from '../types'
3
+
4
+ export * from './managedIdentifierFunctions'
5
+ 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
+ }
@@ -0,0 +1,178 @@
1
+ import { getFirstKeyWithRelation } from '@sphereon/ssi-sdk-ext.did-utils'
2
+ import { calculateJwkThumbprint, JWK, toJwk } from '@sphereon/ssi-sdk-ext.key-utils'
3
+ import { pemOrDerToX509Certificate } from '@sphereon/ssi-sdk-ext.x509-utils'
4
+ import { contextHasDidManager, contextHasKeyManager } from '@sphereon/ssi-sdk.agent-config'
5
+ import { IAgentContext, IIdentifier, IKeyManager } from '@veramo/core'
6
+ import { CryptoEngine, setEngine } from 'pkijs'
7
+ import {
8
+ isManagedIdentifierDidOpts,
9
+ isManagedIdentifierDidResult,
10
+ isManagedIdentifierJwkOpts,
11
+ isManagedIdentifierKidOpts,
12
+ isManagedIdentifierX5cOpts,
13
+ ManagedIdentifierDidOpts,
14
+ ManagedIdentifierDidResult,
15
+ ManagedIdentifierJwkOpts,
16
+ ManagedIdentifierJwkResult,
17
+ ManagedIdentifierKidOpts,
18
+ ManagedIdentifierKidResult,
19
+ ManagedIdentifierOpts,
20
+ ManagedIdentifierResult,
21
+ ManagedIdentifierX5cOpts,
22
+ ManagedIdentifierX5cResult,
23
+ } from '../types'
24
+
25
+ export async function getManagedKidIdentifier(
26
+ opts: ManagedIdentifierKidOpts,
27
+ context: IAgentContext<IKeyManager>
28
+ ): Promise<ManagedIdentifierKidResult> {
29
+ const method = 'kid'
30
+ if (!contextHasKeyManager(context)) {
31
+ return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
32
+ }
33
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? opts.identifier })
34
+ const jwk = toJwk(key.publicKeyHex, key.type, { key })
35
+ const jwkThumbprint = (key.meta?.jwkThumbprint as string) ?? calculateJwkThumbprint({ jwk })
36
+ const kid = opts.kid ?? (key.meta?.verificationMethod?.id as string) ?? jwkThumbprint
37
+ const issuer = opts.issuer ?? kid // The different identifiers should set the value. Defaults to the kid
38
+ return {
39
+ method,
40
+ key,
41
+ jwk,
42
+ jwkThumbprint,
43
+ kid,
44
+ issuer,
45
+ kmsKeyRef: key.kid,
46
+ } satisfies ManagedIdentifierKidResult
47
+ }
48
+
49
+ export async function getManagedDidIdentifier(opts: ManagedIdentifierDidOpts, context: IAgentContext<any>): Promise<ManagedIdentifierDidResult> {
50
+ const method = 'did'
51
+ if (!contextHasDidManager(context)) {
52
+ return Promise.reject(Error(`Cannot get DID identifier if DID Manager plugin is not enabled!`))
53
+ }
54
+
55
+ let identifier: IIdentifier
56
+ if (typeof opts.identifier === 'string') {
57
+ identifier = await context.agent.didManagerGet({ did: opts.identifier.split('#')[0] })
58
+ } else {
59
+ identifier = opts.identifier
60
+ }
61
+
62
+ const did = identifier.did
63
+ const keys = identifier?.keys // fixme: We really want to return the vmRelationship keys here actually
64
+ const extendedKey = await getFirstKeyWithRelation(
65
+ {
66
+ ...opts,
67
+ identifier,
68
+ vmRelationship: opts.vmRelationship ?? 'verificationMethod',
69
+ },
70
+ context
71
+ )
72
+ const key = extendedKey
73
+ const controllerKeyId = identifier.controllerKeyId
74
+ const jwk = toJwk(key.publicKeyHex, key.type, { key })
75
+ const jwkThumbprint = key.meta?.jwkThumbprint ?? calculateJwkThumbprint({ jwk })
76
+ const kid = opts.kid ?? extendedKey.meta?.verificationMethod?.id
77
+ const issuer = opts.issuer ?? did
78
+ return {
79
+ method,
80
+ key,
81
+ did,
82
+ kmsKeyRef: key.kid,
83
+ jwk,
84
+ jwkThumbprint,
85
+ controllerKeyId,
86
+ kid,
87
+ keys,
88
+ issuer,
89
+ identifier,
90
+ }
91
+ }
92
+
93
+ export async function getManagedJwkIdentifier(
94
+ opts: ManagedIdentifierJwkOpts,
95
+ context: IAgentContext<IKeyManager>
96
+ ): Promise<ManagedIdentifierJwkResult> {
97
+ const method = 'jwk'
98
+ const { kid, issuer } = opts
99
+ if (!contextHasKeyManager(context)) {
100
+ return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
101
+ }
102
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? calculateJwkThumbprint({ jwk: opts.identifier }) })
103
+ const jwk = opts.identifier ?? toJwk(key.publicKeyHex, key.type, { key })
104
+ const jwkThumbprint = (key.meta?.jwkThumbprint as string) ?? calculateJwkThumbprint({ jwk })
105
+ // we explicitly do not set the kid and issuer, meaning it can remain null. Normally you do not provide a kid and issuer with Jwks.
106
+ return {
107
+ method,
108
+ key,
109
+ kmsKeyRef: key.kid,
110
+ jwk,
111
+ jwkThumbprint,
112
+ kid,
113
+ issuer,
114
+ } satisfies ManagedIdentifierJwkResult
115
+ }
116
+
117
+ export async function getManagedX5cIdentifier(
118
+ opts: ManagedIdentifierX5cOpts & {
119
+ crypto?: Crypto
120
+ },
121
+ context: IAgentContext<IKeyManager>
122
+ ): Promise<ManagedIdentifierX5cResult> {
123
+ const { kid, issuer } = opts
124
+ const method = 'x5c'
125
+ const x5c = opts.identifier
126
+ if (x5c.length === 0) {
127
+ return Promise.reject(`Cannot resolve x5c when an empty x5c is passed in`)
128
+ } else if (!contextHasKeyManager(context)) {
129
+ return Promise.reject(Error(`Cannot get X5c identifier if KeyManager plugin is not enabled!`))
130
+ }
131
+ const cryptoImpl = opts.crypto ?? crypto
132
+ const certificate = pemOrDerToX509Certificate(x5c[0])
133
+ const cryptoEngine = new CryptoEngine({ name: 'identifier_resolver_managed', crypto: cryptoImpl })
134
+ setEngine(cryptoEngine.name, cryptoEngine)
135
+ const pk = await certificate.getPublicKey(undefined, cryptoEngine)
136
+ const jwk = (await cryptoEngine.subtle.exportKey('jwk', pk)) as JWK
137
+ const jwkThumbprint = calculateJwkThumbprint({ jwk })
138
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? jwkThumbprint })
139
+ // we explicitly do not set the kid and issuer, meaning it can remain null. Normally you do not provide a kid and issuer with x5c.
140
+
141
+ return {
142
+ method,
143
+ x5c,
144
+ certificate,
145
+ jwk,
146
+ jwkThumbprint,
147
+ key,
148
+ kmsKeyRef: key.kid,
149
+ kid,
150
+ issuer,
151
+ } satisfies ManagedIdentifierX5cResult
152
+ }
153
+
154
+ export async function getManagedIdentifier(
155
+ opts: ManagedIdentifierOpts & {
156
+ crypto?: Crypto
157
+ },
158
+ context: IAgentContext<IKeyManager>
159
+ ): Promise<ManagedIdentifierResult> {
160
+ let resolutionResult: ManagedIdentifierResult
161
+ if (isManagedIdentifierKidOpts(opts)) {
162
+ resolutionResult = await getManagedKidIdentifier(opts, context)
163
+ } else if (isManagedIdentifierDidOpts(opts)) {
164
+ resolutionResult = await getManagedDidIdentifier(opts, context)
165
+ } else if (isManagedIdentifierJwkOpts(opts)) {
166
+ resolutionResult = await getManagedJwkIdentifier(opts, context)
167
+ } else if (isManagedIdentifierX5cOpts(opts)) {
168
+ resolutionResult = await getManagedX5cIdentifier(opts, context)
169
+ } else {
170
+ return Promise.reject(Error(`Could not determine identifier method. Please provide explicitly`))
171
+ }
172
+ const { key } = resolutionResult
173
+ if (!key || (isManagedIdentifierDidOpts(opts) && isManagedIdentifierDidResult(resolutionResult) && !resolutionResult.identifier)) {
174
+ console.log(`Cannot find identifier`, opts.identifier)
175
+ return Promise.reject(`Cannot find identifier ${opts.identifier}`)
176
+ }
177
+ return resolutionResult
178
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ const schema = require('../plugin.schema.json')
5
+ export { schema }
6
+ /**
7
+ * @public
8
+ */
9
+ export { IdentifierResolution } from './agent/IdentifierResolution'
10
+ export * from './functions'
11
+ export * from './types'
@@ -0,0 +1,54 @@
1
+ import { IAgentContext, IDIDManager, IKeyManager, IPluginMethodMap } from '@veramo/core'
2
+ import {
3
+ ExternalIdentifierDidOpts,
4
+ ExternalIdentifierDidResult,
5
+ ExternalIdentifierOpts,
6
+ ExternalIdentifierResult,
7
+ ExternalIdentifierX5cOpts,
8
+ ExternalIdentifierX5cResult,
9
+ } from './externalIdentifierTypes'
10
+ import {
11
+ ManagedIdentifierDidOpts,
12
+ ManagedIdentifierDidResult,
13
+ ManagedIdentifierJwkOpts,
14
+ ManagedIdentifierJwkResult,
15
+ ManagedIdentifierKidOpts,
16
+ ManagedIdentifierKidResult,
17
+ ManagedIdentifierOpts,
18
+ ManagedIdentifierResult,
19
+ ManagedIdentifierX5cOpts,
20
+ ManagedIdentifierX5cResult,
21
+ } from './managedIdentifierTypes'
22
+
23
+ /**
24
+ * @public
25
+ */
26
+ export interface IIdentifierResolution extends IPluginMethodMap {
27
+ /**
28
+ * 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
29
+ * @param args
30
+ * @param context
31
+ * @public
32
+ */
33
+ identifierManagedGet(args: ManagedIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierResult>
34
+
35
+ identifierManagedGetByDid(args: ManagedIdentifierDidOpts, context: IAgentContext<IKeyManager & IDIDManager>): Promise<ManagedIdentifierDidResult>
36
+
37
+ identifierManagedGetByKid(args: ManagedIdentifierKidOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierKidResult>
38
+
39
+ identifierManagedGetByJwk(args: ManagedIdentifierJwkOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierJwkResult>
40
+
41
+ identifierManagedGetByX5c(args: ManagedIdentifierX5cOpts, context: IAgentContext<IKeyManager>): Promise<ManagedIdentifierX5cResult>
42
+
43
+ /**
44
+ * Main method for external 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
45
+ * @param args
46
+ * @param context
47
+ * @public
48
+ */
49
+ identifierExternalResolve(args: ExternalIdentifierOpts, context: IAgentContext<any>): Promise<ExternalIdentifierResult>
50
+
51
+ identifierExternalResolveByDid(args: ExternalIdentifierDidOpts, context: IAgentContext<any>): Promise<ExternalIdentifierDidResult>
52
+
53
+ identifierExternalResolveByX5c(args: ExternalIdentifierX5cOpts, context: IAgentContext<any>): Promise<ExternalIdentifierX5cResult>
54
+ }
@@ -0,0 +1,37 @@
1
+ import { JWK } from '@sphereon/ssi-sdk-ext.key-utils'
2
+ import { IIdentifier } from '@veramo/core'
3
+ import { ExternalIdentifierType } from './externalIdentifierTypes'
4
+ import { ManagedIdentifierType } from './managedIdentifierTypes'
5
+
6
+ export interface JwkInfo {
7
+ jwk: JWK
8
+ jwkThumbprint: string
9
+ }
10
+
11
+ export function isDidIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is IIdentifier | string {
12
+ return isIIdentifier(identifier) || (typeof identifier === 'string' && identifier.startsWith('did:'))
13
+ }
14
+
15
+ export function isIIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is IIdentifier {
16
+ return typeof identifier === 'object' && !Array.isArray(identifier) && 'did' in identifier && 'keys' in identifier
17
+ }
18
+
19
+ export function isJwkIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is JWK {
20
+ return typeof identifier === 'object' && !Array.isArray(identifier) && 'kty' in identifier
21
+ }
22
+
23
+ export function isOidcDiscoveryIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is string {
24
+ return typeof identifier === 'string' && identifier.startsWith('http') && identifier.endsWith('/.well-known/openid-configuration')
25
+ }
26
+
27
+ export function isJwksUrlIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is string {
28
+ return typeof identifier === 'string' && identifier.startsWith('http') && identifier.endsWith('jwks.json')
29
+ }
30
+
31
+ export function isKidIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is string {
32
+ return typeof identifier === 'string' && !identifier.startsWith('did:')
33
+ }
34
+
35
+ export function isX5cIdentifier(identifier: ManagedIdentifierType | ExternalIdentifierType): identifier is string[] {
36
+ return Array.isArray(identifier) && identifier.length > 0 // todo: Do we want to do additional validation? We know it must be DER and thus hex for instance
37
+ }