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

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 (60) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +433 -0
  3. package/dist/agent/IdentifierResolution.d.ts +33 -0
  4. package/dist/agent/IdentifierResolution.d.ts.map +1 -0
  5. package/dist/agent/IdentifierResolution.js +93 -0
  6. package/dist/agent/IdentifierResolution.js.map +1 -0
  7. package/dist/functions/LegacySupport.d.ts +12 -0
  8. package/dist/functions/LegacySupport.d.ts.map +1 -0
  9. package/dist/functions/LegacySupport.js +39 -0
  10. package/dist/functions/LegacySupport.js.map +1 -0
  11. package/dist/functions/externalIdentifierFunctions.d.ts +10 -0
  12. package/dist/functions/externalIdentifierFunctions.d.ts.map +1 -0
  13. package/dist/functions/externalIdentifierFunctions.js +167 -0
  14. package/dist/functions/externalIdentifierFunctions.js.map +1 -0
  15. package/dist/functions/index.d.ts +4 -0
  16. package/dist/functions/index.d.ts.map +1 -0
  17. package/dist/functions/index.js +20 -0
  18. package/dist/functions/index.js.map +1 -0
  19. package/dist/functions/managedIdentifierFunctions.d.ts +28 -0
  20. package/dist/functions/managedIdentifierFunctions.d.ts.map +1 -0
  21. package/dist/functions/managedIdentifierFunctions.js +252 -0
  22. package/dist/functions/managedIdentifierFunctions.js.map +1 -0
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +30 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/tsdoc-metadata.json +11 -0
  28. package/dist/types/IIdentifierResolution.d.ts +37 -0
  29. package/dist/types/IIdentifierResolution.d.ts.map +1 -0
  30. package/dist/types/IIdentifierResolution.js +16 -0
  31. package/dist/types/IIdentifierResolution.js.map +1 -0
  32. package/dist/types/common.d.ts +17 -0
  33. package/dist/types/common.d.ts.map +1 -0
  34. package/dist/types/common.js +40 -0
  35. package/dist/types/common.js.map +1 -0
  36. package/dist/types/externalIdentifierTypes.d.ts +80 -0
  37. package/dist/types/externalIdentifierTypes.d.ts.map +1 -0
  38. package/dist/types/externalIdentifierTypes.js +35 -0
  39. package/dist/types/externalIdentifierTypes.js.map +1 -0
  40. package/dist/types/index.d.ts +5 -0
  41. package/dist/types/index.d.ts.map +1 -0
  42. package/dist/types/index.js +21 -0
  43. package/dist/types/index.js.map +1 -0
  44. package/dist/types/managedIdentifierTypes.d.ts +98 -0
  45. package/dist/types/managedIdentifierTypes.d.ts.map +1 -0
  46. package/dist/types/managedIdentifierTypes.js +50 -0
  47. package/dist/types/managedIdentifierTypes.js.map +1 -0
  48. package/package.json +68 -0
  49. package/plugin.schema.json +2393 -0
  50. package/src/agent/IdentifierResolution.ts +112 -0
  51. package/src/functions/LegacySupport.ts +50 -0
  52. package/src/functions/externalIdentifierFunctions.ts +183 -0
  53. package/src/functions/index.ts +3 -0
  54. package/src/functions/managedIdentifierFunctions.ts +278 -0
  55. package/src/index.ts +11 -0
  56. package/src/types/IIdentifierResolution.ts +79 -0
  57. package/src/types/common.ts +47 -0
  58. package/src/types/externalIdentifierTypes.ts +119 -0
  59. package/src/types/index.ts +4 -0
  60. package/src/types/managedIdentifierTypes.ts +157 -0
@@ -0,0 +1,112 @@
1
+ import { IAgentContext, IAgentPlugin, IDIDManager, IKeyManager } from '@veramo/core'
2
+ import { ensureManagedIdentifierResult, ManagedIdentifierKeyOpts, ManagedIdentifierKeyResult, ManagedIdentifierOptsOrResult, schema } from '..'
3
+ import { 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
+ ManagedIdentifierResult,
19
+ ManagedIdentifierX5cOpts,
20
+ ManagedIdentifierX5cResult,
21
+ } from '../types'
22
+
23
+ /**
24
+ * @public
25
+ */
26
+ export class IdentifierResolution implements IAgentPlugin {
27
+ private readonly _crypto: Crypto
28
+
29
+ readonly schema = schema.IMnemonicInfoGenerator
30
+ readonly methods: IIdentifierResolution = {
31
+ identifierManagedGet: this.identifierGetManaged.bind(this),
32
+ identifierManagedGetByDid: this.identifierGetManagedByDid.bind(this),
33
+ identifierManagedGetByKid: this.identifierGetManagedByKid.bind(this),
34
+ identifierManagedGetByJwk: this.identifierGetManagedByJwk.bind(this),
35
+ identifierManagedGetByX5c: this.identifierGetManagedByX5c.bind(this),
36
+ identifierManagedGetByKey: this.identifierGetManagedByKey.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 other methods below) as we want to
54
+ * integrate a plugin for anomaly detection. Having a single method helps
55
+ * @param args
56
+ * @param context
57
+ * @private
58
+ */
59
+ private async identifierGetManaged(
60
+ args: ManagedIdentifierOptsOrResult,
61
+ context: IAgentContext<IKeyManager & IIdentifierResolution>
62
+ ): Promise<ManagedIdentifierResult> {
63
+ return await ensureManagedIdentifierResult({ ...args, crypto: this._crypto }, context)
64
+ }
65
+
66
+ private async identifierGetManagedByDid(
67
+ args: ManagedIdentifierDidOpts,
68
+ context: IAgentContext<IKeyManager & IDIDManager & IIdentifierResolution>
69
+ ): Promise<ManagedIdentifierDidResult> {
70
+ return (await this.identifierGetManaged({ ...args, method: 'did' }, context)) as ManagedIdentifierDidResult
71
+ }
72
+
73
+ private async identifierGetManagedByKid(
74
+ args: ManagedIdentifierKidOpts,
75
+ context: IAgentContext<IKeyManager & IIdentifierResolution>
76
+ ): Promise<ManagedIdentifierKidResult> {
77
+ return (await this.identifierGetManaged({ ...args, method: 'kid' }, context)) as ManagedIdentifierKidResult
78
+ }
79
+
80
+ private async identifierGetManagedByKey(
81
+ args: ManagedIdentifierKeyOpts,
82
+ context: IAgentContext<IKeyManager & IIdentifierResolution>
83
+ ): Promise<ManagedIdentifierKeyResult> {
84
+ return (await this.identifierGetManaged({ ...args, method: 'key' }, context)) as ManagedIdentifierKeyResult
85
+ }
86
+
87
+ private async identifierGetManagedByJwk(
88
+ args: ManagedIdentifierJwkOpts,
89
+ context: IAgentContext<IKeyManager & IIdentifierResolution>
90
+ ): Promise<ManagedIdentifierJwkResult> {
91
+ return (await this.identifierGetManaged({ ...args, method: 'jwk' }, context)) as ManagedIdentifierJwkResult
92
+ }
93
+
94
+ private async identifierGetManagedByX5c(
95
+ args: ManagedIdentifierX5cOpts,
96
+ context: IAgentContext<IKeyManager & IIdentifierResolution>
97
+ ): Promise<ManagedIdentifierX5cResult> {
98
+ return (await this.identifierGetManaged({ ...args, method: 'x5c' }, context)) as ManagedIdentifierX5cResult
99
+ }
100
+
101
+ private async identifierResolveExternal(args: ExternalIdentifierOpts, context: IAgentContext<IKeyManager>): Promise<ExternalIdentifierResult> {
102
+ return await resolveExternalIdentifier({ ...args, crypto: this._crypto }, context)
103
+ }
104
+
105
+ private async identifierExternalResolveByDid(args: ExternalIdentifierDidOpts, context: IAgentContext<any>): Promise<ExternalIdentifierDidResult> {
106
+ return (await this.identifierResolveExternal({ ...args, method: 'did' }, context)) as ExternalIdentifierDidResult
107
+ }
108
+
109
+ private async identifierExternalResolveByX5c(args: ExternalIdentifierX5cOpts, context: IAgentContext<any>): Promise<ExternalIdentifierX5cResult> {
110
+ return (await this.identifierResolveExternal({ ...args, method: 'x5c' }, context)) as ExternalIdentifierX5cResult
111
+ }
112
+ }
@@ -0,0 +1,50 @@
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
+ (typeof opts.didOpts?.idOpts.identifier === 'object' ? (opts.didOpts?.idOpts.identifier as IIdentifier).keys[0].kid : undefined)
23
+ if (!kmsKeyRef) {
24
+ throw Error('Key ref is needed for access token signer')
25
+ }
26
+ return {
27
+ kmsKeyRef: opts.keyRef ?? kmsKeyRef,
28
+ identifier: kmsKeyRef,
29
+ issuer: opts.iss,
30
+ } satisfies ManagedIdentifierDidOpts
31
+ } else {
32
+ const idOpts = opts.idOpts
33
+ if (opts.keyRef && !idOpts.kmsKeyRef) {
34
+ // legacy way
35
+ console.warn(
36
+ `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`
37
+ )
38
+ idOpts.kmsKeyRef = opts.keyRef
39
+ }
40
+ if (opts.iss && !idOpts.issuer) {
41
+ // legacy way
42
+ console.warn(
43
+ `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`
44
+ )
45
+ idOpts.issuer = opts.iss
46
+ }
47
+
48
+ return idOpts
49
+ }
50
+ }
@@ -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,3 @@
1
+ export * from './managedIdentifierFunctions'
2
+ export * from './externalIdentifierFunctions'
3
+ export * from './LegacySupport'
@@ -0,0 +1,278 @@
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, IKey, IKeyManager } from '@veramo/core'
6
+ import { CryptoEngine, setEngine } from 'pkijs'
7
+ import {
8
+ IIdentifierResolution,
9
+ isManagedIdentifierDidOpts,
10
+ isManagedIdentifierDidResult,
11
+ isManagedIdentifierJwkOpts,
12
+ isManagedIdentifierJwkResult,
13
+ isManagedIdentifierKeyOpts,
14
+ isManagedIdentifierKeyResult,
15
+ isManagedIdentifierKidOpts,
16
+ isManagedIdentifierX5cOpts,
17
+ ManagedIdentifierDidOpts,
18
+ ManagedIdentifierDidResult,
19
+ ManagedIdentifierJwkOpts,
20
+ ManagedIdentifierJwkResult,
21
+ ManagedIdentifierKeyOpts,
22
+ ManagedIdentifierKeyResult,
23
+ ManagedIdentifierKidOpts,
24
+ ManagedIdentifierKidResult,
25
+ ManagedIdentifierOptsOrResult,
26
+ ManagedIdentifierResult,
27
+ ManagedIdentifierX5cOpts,
28
+ ManagedIdentifierX5cResult,
29
+ } from '../types'
30
+
31
+ export async function getManagedKidIdentifier(
32
+ opts: ManagedIdentifierKidOpts,
33
+ context: IAgentContext<IKeyManager>
34
+ ): Promise<ManagedIdentifierKidResult> {
35
+ const method = 'kid'
36
+ if (!contextHasKeyManager(context)) {
37
+ return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
38
+ }
39
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? opts.identifier })
40
+ const jwk = toJwk(key.publicKeyHex, key.type, { key })
41
+ const jwkThumbprint = (key.meta?.jwkThumbprint as string) ?? calculateJwkThumbprint({ jwk })
42
+ const kid = opts.kid ?? (key.meta?.verificationMethod?.id as string) ?? jwkThumbprint
43
+ const issuer = opts.issuer ?? kid // The different identifiers should set the value. Defaults to the kid
44
+ return {
45
+ method,
46
+ key,
47
+ identifier: opts.identifier,
48
+ jwk,
49
+ jwkThumbprint,
50
+ kid,
51
+ issuer,
52
+ kmsKeyRef: key.kid,
53
+ opts,
54
+ } satisfies ManagedIdentifierKidResult
55
+ }
56
+
57
+ function isManagedIdentifierResult(identifier: ManagedIdentifierOptsOrResult & { crypto?: Crypto }): identifier is ManagedIdentifierResult {
58
+ return 'key' in identifier && 'kmsKeyRef' in identifier && 'method' in identifier && 'opts' in identifier
59
+ }
60
+
61
+ /**
62
+ * Allows to get a managed identifier result in case identifier options are passed in, but returns the identifier directly in case results are passed in. This means resolution can have happened before, or happens in this method
63
+ * @param identifier
64
+ * @param context
65
+ */
66
+ export async function ensureManagedIdentifierResult(
67
+ identifier: ManagedIdentifierOptsOrResult & {
68
+ crypto?: Crypto
69
+ },
70
+ context: IAgentContext<IKeyManager>
71
+ ): Promise<ManagedIdentifierResult> {
72
+ const { lazyDisabled = false } = identifier
73
+ return !lazyDisabled && isManagedIdentifierResult(identifier) ? identifier : await getManagedIdentifier(identifier, context)
74
+ }
75
+
76
+ /**
77
+ * This function is just a convenience function to get a common result. The user already apparently had a key, so could have called the kid version as well
78
+ * @param opts
79
+ * @param _context
80
+ */
81
+ export async function getManagedKeyIdentifier(opts: ManagedIdentifierKeyOpts, _context?: IAgentContext<any>): Promise<ManagedIdentifierKeyResult> {
82
+ const method = 'key'
83
+ const key: IKey = opts.identifier
84
+ if (opts.kmsKeyRef && opts.kmsKeyRef !== key.kid) {
85
+ return Promise.reject(Error(`Cannot get a managed key object by providing a key and a kmsKeyRef that are different.}`))
86
+ }
87
+ const jwk = toJwk(key.publicKeyHex, key.type, { key })
88
+ const jwkThumbprint = (key.meta?.jwkThumbprint as string) ?? calculateJwkThumbprint({ jwk })
89
+ const kid = opts.kid ?? (key.meta?.verificationMethod?.id as string) ?? jwkThumbprint
90
+ const issuer = opts.issuer ?? kid // The different identifiers should set the value. Defaults to the kid
91
+ return {
92
+ method,
93
+ key,
94
+ identifier: key,
95
+ jwk,
96
+ jwkThumbprint,
97
+ kid,
98
+ issuer,
99
+ kmsKeyRef: key.kid,
100
+ opts,
101
+ } satisfies ManagedIdentifierKeyResult
102
+ }
103
+
104
+ export async function getManagedDidIdentifier(opts: ManagedIdentifierDidOpts, context: IAgentContext<any>): Promise<ManagedIdentifierDidResult> {
105
+ const method = 'did'
106
+ if (!contextHasDidManager(context)) {
107
+ return Promise.reject(Error(`Cannot get DID identifier if DID Manager plugin is not enabled!`))
108
+ }
109
+
110
+ let identifier: IIdentifier
111
+ if (typeof opts.identifier === 'string') {
112
+ identifier = await context.agent.didManagerGet({ did: opts.identifier.split('#')[0] })
113
+ } else {
114
+ identifier = opts.identifier
115
+ }
116
+
117
+ const did = identifier.did
118
+ const keys = identifier?.keys // fixme: We really want to return the vmRelationship keys here actually
119
+ const extendedKey = await getFirstKeyWithRelation(
120
+ {
121
+ ...opts,
122
+ identifier,
123
+ vmRelationship: opts.vmRelationship ?? 'verificationMethod',
124
+ },
125
+ context
126
+ )
127
+ const key = extendedKey
128
+ const controllerKeyId = identifier.controllerKeyId
129
+ const jwk = toJwk(key.publicKeyHex, key.type, { key })
130
+ const jwkThumbprint = key.meta?.jwkThumbprint ?? calculateJwkThumbprint({ jwk })
131
+ let kid = opts.kid ?? extendedKey.meta?.verificationMethod?.id
132
+ if (!kid.startsWith(did)) {
133
+ // Make sure we create a fully qualified kid
134
+ const hash = kid.startsWith('#') ? '' : '#'
135
+ kid = `${did}${hash}${kid}`
136
+ }
137
+ const issuer = opts.issuer ?? did
138
+ return {
139
+ method,
140
+ key,
141
+ did,
142
+ kmsKeyRef: key.kid,
143
+ jwk,
144
+ jwkThumbprint,
145
+ controllerKeyId,
146
+ kid,
147
+ keys,
148
+ issuer,
149
+ identifier,
150
+ opts,
151
+ }
152
+ }
153
+
154
+ export async function getManagedJwkIdentifier(
155
+ opts: ManagedIdentifierJwkOpts,
156
+ context: IAgentContext<IKeyManager>
157
+ ): Promise<ManagedIdentifierJwkResult> {
158
+ const method = 'jwk'
159
+ const { kid, issuer } = opts
160
+ if (!contextHasKeyManager(context)) {
161
+ return Promise.reject(Error(`Cannot get Key/JWK identifier if KeyManager plugin is not enabled!`))
162
+ }
163
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? calculateJwkThumbprint({ jwk: opts.identifier }) })
164
+ const jwk = opts.identifier ?? toJwk(key.publicKeyHex, key.type, { key })
165
+ const jwkThumbprint = (key.meta?.jwkThumbprint as string) ?? calculateJwkThumbprint({ jwk })
166
+ // 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.
167
+ return {
168
+ method,
169
+ key,
170
+ kmsKeyRef: key.kid,
171
+ identifier: jwk,
172
+ jwk,
173
+ jwkThumbprint,
174
+ kid,
175
+ issuer,
176
+ opts,
177
+ } satisfies ManagedIdentifierJwkResult
178
+ }
179
+
180
+ export async function getManagedX5cIdentifier(
181
+ opts: ManagedIdentifierX5cOpts & {
182
+ crypto?: Crypto
183
+ },
184
+ context: IAgentContext<IKeyManager>
185
+ ): Promise<ManagedIdentifierX5cResult> {
186
+ const { kid, issuer } = opts
187
+ const method = 'x5c'
188
+ const x5c = opts.identifier
189
+ if (x5c.length === 0) {
190
+ return Promise.reject(`Cannot resolve x5c when an empty x5c is passed in`)
191
+ } else if (!contextHasKeyManager(context)) {
192
+ return Promise.reject(Error(`Cannot get X5c identifier if KeyManager plugin is not enabled!`))
193
+ }
194
+ const cryptoImpl = opts.crypto ?? crypto
195
+ const certificate = pemOrDerToX509Certificate(x5c[0])
196
+ const cryptoEngine = new CryptoEngine({ name: 'identifier_resolver_managed', crypto: cryptoImpl })
197
+ setEngine(cryptoEngine.name, cryptoEngine)
198
+ const pk = await certificate.getPublicKey(undefined, cryptoEngine)
199
+ const jwk = (await cryptoEngine.subtle.exportKey('jwk', pk)) as JWK
200
+ const jwkThumbprint = calculateJwkThumbprint({ jwk })
201
+ const key = await context.agent.keyManagerGet({ kid: opts.kmsKeyRef ?? jwkThumbprint })
202
+ // 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.
203
+
204
+ return {
205
+ method,
206
+ x5c,
207
+ identifier: x5c,
208
+ certificate,
209
+ jwk,
210
+ jwkThumbprint,
211
+ key,
212
+ kmsKeyRef: key.kid,
213
+ kid,
214
+ issuer,
215
+ opts,
216
+ } satisfies ManagedIdentifierX5cResult
217
+ }
218
+
219
+ export async function getManagedIdentifier(
220
+ opts: ManagedIdentifierOptsOrResult & {
221
+ crypto?: Crypto
222
+ },
223
+ context: IAgentContext<IKeyManager>
224
+ ): Promise<ManagedIdentifierResult> {
225
+ let resolutionResult: ManagedIdentifierResult
226
+ if (isManagedIdentifierResult(opts)) {
227
+ opts
228
+ }
229
+ if (isManagedIdentifierKidOpts(opts)) {
230
+ resolutionResult = await getManagedKidIdentifier(opts, context)
231
+ } else if (isManagedIdentifierDidOpts(opts)) {
232
+ resolutionResult = await getManagedDidIdentifier(opts, context)
233
+ } else if (isManagedIdentifierJwkOpts(opts)) {
234
+ resolutionResult = await getManagedJwkIdentifier(opts, context)
235
+ } else if (isManagedIdentifierX5cOpts(opts)) {
236
+ resolutionResult = await getManagedX5cIdentifier(opts, context)
237
+ } else if (isManagedIdentifierKeyOpts(opts)) {
238
+ resolutionResult = await getManagedKeyIdentifier(opts, context)
239
+ } else {
240
+ return Promise.reject(Error(`Could not determine identifier method. Please provide explicitly`))
241
+ }
242
+ const { key } = resolutionResult
243
+ if (!key || (isManagedIdentifierDidOpts(opts) && isManagedIdentifierDidResult(resolutionResult) && !resolutionResult.identifier)) {
244
+ console.log(`Cannot find identifier`, opts.identifier)
245
+ return Promise.reject(`Cannot find identifier ${opts.identifier}`)
246
+ }
247
+ return resolutionResult
248
+ }
249
+
250
+ export async function managedIdentifierToKeyResult(
251
+ identifier: ManagedIdentifierOptsOrResult,
252
+ context: IAgentContext<IIdentifierResolution & IKeyManager>
253
+ ): Promise<ManagedIdentifierKeyResult> {
254
+ const resolved = await ensureManagedIdentifierResult(identifier, context)
255
+ if (isManagedIdentifierKeyResult(resolved)) {
256
+ return resolved
257
+ }
258
+ return {
259
+ ...resolved,
260
+ method: 'key',
261
+ identifier: resolved.key,
262
+ } satisfies ManagedIdentifierKeyResult
263
+ }
264
+
265
+ export async function managedIdentifierToJwk(
266
+ identifier: ManagedIdentifierOptsOrResult,
267
+ context: IAgentContext<IIdentifierResolution & IKeyManager>
268
+ ): Promise<ManagedIdentifierJwkResult> {
269
+ const resolved = await ensureManagedIdentifierResult(identifier, context)
270
+ if (isManagedIdentifierJwkResult(resolved)) {
271
+ return resolved
272
+ }
273
+ return {
274
+ ...resolved,
275
+ method: 'jwk',
276
+ identifier: resolved.jwk,
277
+ } satisfies ManagedIdentifierJwkResult
278
+ }
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'