Skip to content

Commit e441cc1

Browse files
authored
fix: improve did key id resolving (#2624)
1 parent ab02f5e commit e441cc1

3 files changed

Lines changed: 50 additions & 3 deletions

File tree

.changeset/odd-deer-create.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@credo-ts/core": patch
3+
---
4+
5+
fix: improve did key id resolving. We used `startsWith` to match, but that has loopholes, and did not correctly handle all relative key ids. We now 'compact' each key id (remove the did prefix) but only if the keyId starts with the did document id, and compares them.

packages/core/src/modules/dids/domain/DidDocument.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export class DidDocument {
113113
// TODO: once we use JSON-LD we should use that to resolve references in did documents.
114114
// for now we check whether the key id ends with the keyId.
115115
// so if looking for #123 and key.id is did:key:123#123, it is valid. But #123 as key.id is also valid
116-
const verificationMethod = this.verificationMethod?.find((key) => key.id.endsWith(keyId))
116+
const verificationMethod = this.verificationMethod?.find((key) => this.matchKeyId(keyId, key.id))
117117

118118
if (!verificationMethod) {
119119
throw new CredoError(`Unable to locate verification method with id '${keyId}'`)
@@ -136,10 +136,10 @@ export class DidDocument {
136136

137137
for (const purpose of purposes) {
138138
for (const key of this[purpose] ?? []) {
139-
if (typeof key === 'string' && key.endsWith(keyId)) {
139+
if (typeof key === 'string' && this.matchKeyId(keyId, key)) {
140140
return this.dereferenceVerificationMethod(key)
141141
}
142-
if (typeof key !== 'string' && key.id.endsWith(keyId)) {
142+
if (typeof key !== 'string' && this.matchKeyId(keyId, key.id)) {
143143
return key
144144
}
145145
}
@@ -148,6 +148,16 @@ export class DidDocument {
148148
throw new CredoError(`Unable to locate verification method with id '${keyId}' in purposes ${purposes}`)
149149
}
150150

151+
private matchKeyId(externalKeyId: string, didDocumentKeyId: string) {
152+
// Compact is did removed from start but only if it matches the id of this document.
153+
const compactExternalKeyId = externalKeyId.startsWith(this.id) ? externalKeyId.slice(this.id.length) : externalKeyId
154+
const compactDidDocumentKeyId = didDocumentKeyId.startsWith(this.id)
155+
? didDocumentKeyId.slice(this.id.length)
156+
: didDocumentKeyId
157+
158+
return compactExternalKeyId === compactDidDocumentKeyId
159+
}
160+
151161
public findVerificationMethodByPublicKey(publicJwk: PublicJwk, allowedPurposes?: DidVerificationMethods[]) {
152162
const allPurposes: DidVerificationMethods[] = [
153163
'authentication',

packages/core/src/modules/dids/domain/__tests__/DidDocument.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,38 @@ describe('Did | DidDocument', () => {
176176
}
177177
})
178178

179+
it('should resolve both relative and absolute keyId combinations', () => {
180+
const didDocument = DidDocument.fromJSON({
181+
'@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/jws-2020/v1'],
182+
id: 'did:web:verifier.dev.eduid.nl',
183+
verificationMethod: [
184+
{
185+
id: 'did:web:verifier.dev.eduid.nl#0',
186+
type: 'JsonWebKey2020',
187+
publicKeyJwk: {
188+
kty: 'EC',
189+
crv: 'P-256',
190+
kid: '02435f281d2d4a2bc2eed6a87bc24a4e7ba1f7f7276c9bc1ffdd6e27b58638d9be',
191+
use: 'sig',
192+
key_ops: ['verify'],
193+
alg: 'ES256',
194+
x: 'Q18oHS1KK8Lu1qh7wkpOe6H39ydsm8H_3W4ntYY42b4',
195+
y: 'zF-vLyHCwUNlVjf8xC4vgZzZ6mJFEACXe-A4jOU3YJI',
196+
},
197+
controller: 'did:web:verifier.dev.eduid.nl',
198+
},
199+
],
200+
authentication: ['#0'],
201+
assertionMethod: ['#0'],
202+
capabilityDelegation: ['#0'],
203+
capabilityInvocation: ['#0'],
204+
})
205+
206+
expect(didDocument.dereferenceKey('did:web:verifier.dev.eduid.nl#0', ['authentication'])).toEqual(
207+
didDocument.verificationMethod?.[0]
208+
)
209+
})
210+
179211
it('should correctly transforms DidDoc class to Json', () => {
180212
const didDocumentJson = JsonTransformer.toJSON(didDocumentInstance)
181213

0 commit comments

Comments
 (0)