Skip to content

Commit

Permalink
fix(credential-ld): fix Ed25519Signature2020 verification (#1166)
Browse files Browse the repository at this point in the history
* fix(utils): allow x25519-pub multicodec when converting publicKeyMultibase to bytes, rename util function

* fix(credential-ld): pre-process DID doc for Ed25519Signature2020

* fix(credential-ld): return correct signature bytes for Ed25519-2020 suite

* feat(credential-ld): add schema.org and X25519_2020 context

* fix(remote-server): improve LD @context compliance in web-did-doc-router

* fix(credential-ld): fix document loader for Ed25519-2020 suite

---------

Co-authored-by: nickreynolds <nicholas.s.reynolds@gmail.com>
  • Loading branch information
mirceanis and nickreynolds authored Apr 14, 2023
1 parent ad79a22 commit c965fd5
Show file tree
Hide file tree
Showing 51 changed files with 19,554 additions and 5,990 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-and-test-on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
with:
node-version: 18
cache: 'pnpm'
- run: pnpm add -g pnpm

- run: pnpm install
- run: pnpm build
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/build-test-publish-on-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
with:
node-version: 18
cache: 'pnpm'
- run: pnpm add -g pnpm

- run: pnpm install
- run: pnpm build
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"Keypair",
"arrayify",
"ethersproject"
]
],
"jest.autoRun": "off"
}
2 changes: 1 addition & 1 deletion __tests__/localAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ import credentialStatus from './shared/credentialStatus'
import ethrDidFlowSigned from "./shared/ethrDidFlowSigned";
import didCommWithPeerDidFlow from './shared/didCommWithPeerDidFlow.js'

jest.setTimeout(60000)
jest.setTimeout(120000)

const infuraProjectId = '3586660d179141e3801c3895de1c2eba'
const secretKey = '29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c'
Expand Down
2 changes: 1 addition & 1 deletion __tests__/localJsonStoreAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ import utils from './shared/utils'
import { JsonFileStore } from './utils/json-file-store'
import credentialStatus from './shared/credentialStatus'

jest.setTimeout(60000)
jest.setTimeout(120000)

const infuraProjectId = '3586660d179141e3801c3895de1c2eba'
const secretKey = '29739248cad1bd1a0fc4d9b75cd4d2990de535baf5caadfdf8d8f86664aa830c'
Expand Down
2 changes: 1 addition & 1 deletion __tests__/localMemoryStoreAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ import utils from './shared/utils.js'
import credentialStatus from './shared/credentialStatus.js'
import credentialInterop from './shared/credentialInterop.js'

jest.setTimeout(60000)
jest.setTimeout(120000)

const infuraProjectId = '3586660d179141e3801c3895de1c2eba'

Expand Down
2 changes: 1 addition & 1 deletion __tests__/restAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ import didDiscovery from './shared/didDiscovery'
import utils from './shared/utils'
import credentialStatus from './shared/credentialStatus'

jest.setTimeout(60000)
jest.setTimeout(120000)

const databaseFile = `./tmp/rest-database-${Math.random().toPrecision(5)}.sqlite`
const infuraProjectId = '3586660d179141e3801c3895de1c2eba'
Expand Down
4 changes: 2 additions & 2 deletions __tests__/shared/credentialInterop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default (testContext: {
let credential = (await fs.promises.readFile(`./__tests__/fixtures/${text}`, 'utf8')).toString()
credential = JSON.parse(credential)

const { verified, error } = await agent.verifyCredential({ credential })
expect(verified).toBe(true)
const result = await agent.verifyCredential({ credential })
expect(result.verified).toBe(true)
})
})
}
17 changes: 9 additions & 8 deletions __tests__/shared/resolveDid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,32 @@ export default (testContext: {
let identifier: IIdentifier = await agent.didManagerCreate({
// this expects the `did:ethr` provider to matchPrefix and use the `arbitrum:goerli` network specifier
provider: 'did:pkh',
options: { chainId: "1"}
});
options: { chainId: '1' },
})

const result = await agent.resolveDid({ didUrl: identifier.did});
const result = await agent.resolveDid({ didUrl: identifier.did })
const didDoc = result.didDocument
expect(didDoc?.id).toEqual(identifier.did)
expect(result).toHaveProperty('didDocumentMetadata')
expect(result).toHaveProperty('didResolutionMetadata')

//let cred = await agent.createVerifiableCredential()
});
})

it('should resolve did:jwk', async () => {
let identifier: IIdentifier = await agent.didManagerCreate({
provider: 'did:jwk',
// keyType supports 'Secp256k1', 'Secp256r1', 'Ed25519', 'X25519'
options: {
keyType: "Ed25519"
}
keyType: 'Ed25519',
},
})
const result = await agent.resolveDid({ didUrl: identifier.did})
const result = await agent.resolveDid({ didUrl: identifier.did })
const didDoc = result.didDocument
expect(didDoc?.id).toEqual(identifier.did)
expect(result).toHaveProperty('didDocumentMetadata')
expect(result).toHaveProperty('didResolutionMetadata')
});
})

it('should resolve imported fake did', async () => {
const did = 'did:fake:myfakedid'
Expand Down Expand Up @@ -112,6 +112,7 @@ export default (testContext: {
keyAgreement: ['did:fake:myfakedid#fake-key-1'],
authentication: ['did:fake:myfakedid#fake-key-1'],
assertionMethod: ['did:fake:myfakedid#fake-key-1'],
'@context': ['https://www.w3.org/ns/did/v1', 'https://w3id.org/security/suites/ed25519-2018/v1'],
})
expect(resolved).toHaveProperty('didDocumentMetadata')
expect(resolved).toHaveProperty('didResolutionMetadata')
Expand Down
2 changes: 1 addition & 1 deletion __tests__/shared/verifiableDataLD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export default (testContext: {
expect(credential).toHaveProperty('proof.jws')
expect(credential['type']).toEqual(['VerifiableCredential', 'DiscordKudos'])

const result = await agent.verifyCredential({
const result = await agent.verifyCredential({
credential,
fetchRemoteContexts: true
})
Expand Down
143 changes: 143 additions & 0 deletions packages/credential-ld/src/__tests__/issue-verify-ed25519-2020.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {
createAgent,
CredentialPayload,
ICredentialPlugin,
IDIDManager,
IIdentifier,
IKeyManager,
IResolver,
TAgent,
} from '../../../core/src'
import { CredentialPlugin } from '../../../credential-w3c/src'
import { DIDManager, MemoryDIDStore } from '../../../did-manager/src'
import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '../../../key-manager/src'
import { KeyManagementSystem } from '../../../kms-local/src'
import { DIDResolverPlugin } from '../../../did-resolver/src'
import { ContextDoc } from '../types'
import { CredentialIssuerLD } from '../action-handler'
import { LdDefaultContexts } from '../ld-default-contexts'
import { VeramoEd25519Signature2020 } from '../suites/Ed25519Signature2020'
import { Resolver } from 'did-resolver'
import { FakeDidProvider, FakeDidResolver } from '../../../test-utils/src/fake-did'
import { jest } from '@jest/globals'

jest.setTimeout(300000)

const customContext: Record<string, ContextDoc> = {
'custom:example.context': {
'@context': {
nothing: 'custom:example.context#blank',
},
},
}

describe('credential-LD full flow', () => {
let didFakeIdentifier: IIdentifier
let agent: TAgent<IResolver & IKeyManager & IDIDManager & ICredentialPlugin>

beforeAll(async () => {
agent = createAgent({
plugins: [
new KeyManager({
store: new MemoryKeyStore(),
kms: {
local: new KeyManagementSystem(new MemoryPrivateKeyStore()),
},
}),
new DIDManager({
providers: {
'did:fake': new FakeDidProvider(),
},
store: new MemoryDIDStore(),
defaultProvider: 'did:fake',
}),
new DIDResolverPlugin({
resolver: new Resolver({
...new FakeDidResolver(() => agent, true).getDidFakeResolver(),
}),
}),
new CredentialPlugin(),
new CredentialIssuerLD({
contextMaps: [LdDefaultContexts, customContext],
suites: [new VeramoEd25519Signature2020()],
}),
],
})
didFakeIdentifier = await agent.didManagerImport({
did: 'did:fake:z6MkgbqNU4uF9NKSz5BqJQ4XKVHuQZYcUZP8pXGsJC8nTHwo',
keys: [
{
type: 'Ed25519',
kid: 'didcomm-senderKey-1',
publicKeyHex: '1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a',
privateKeyHex:
'b57103882f7c66512dc96777cbafbeb2d48eca1e7a867f5a17a84e9a6740f7dc1fe9b397c196ab33549041b29cf93be29b9f2bdd27322f05844112fad97ff92a',
kms: 'local',
},
],
services: [
{
id: 'msg1',
type: 'DIDCommMessaging',
serviceEndpoint: 'http://localhost:3002/messaging',
},
],
provider: 'did:fake',
alias: 'sender',
})
})

it('works with Ed25519Signature2020 credential', async () => {
const credential: CredentialPayload = {
issuer: didFakeIdentifier.did,
'@context': ['custom:example.context'],
credentialSubject: {
nothing: 'else matters',
},
}
const verifiableCredential = await agent.createVerifiableCredential({
credential,
proofFormat: 'lds',
})

expect(verifiableCredential).toBeDefined()

const result = await agent.verifyCredential({
credential: verifiableCredential,
})

expect(result.verified).toBe(true)
})

it('works with Ed25519Signature2020 credential and presentation', async () => {
const credential: CredentialPayload = {
issuer: didFakeIdentifier.did,
'@context': ['custom:example.context'],
credentialSubject: {
nothing: 'else matters',
},
}
const verifiableCredential1 = await agent.createVerifiableCredential({
credential,
proofFormat: 'lds',
})

const verifiablePresentation = await agent.createVerifiablePresentation({
presentation: {
verifiableCredential: [verifiableCredential1],
holder: didFakeIdentifier.did,
},
challenge: 'VERAMO',
proofFormat: 'lds',
})

expect(verifiablePresentation).toBeDefined()

const result = await agent.verifyPresentation({
presentation: verifiablePresentation,
challenge: 'VERAMO',
})

expect(result.verified).toBe(true)
})
})
64 changes: 0 additions & 64 deletions packages/credential-ld/src/contexts/did_v0.11.json

This file was deleted.

Loading

0 comments on commit c965fd5

Please sign in to comment.