Skip to content

Commit

Permalink
Update DID DHT Key Type to EdDSA (#653)
Browse files Browse the repository at this point in the history
* updates to did dht spec

* update test

* linter

* fix security audit

* turn on test vectors and update test vector json

* updates

* remove comment

* update and put thumbprint in vectors temporarily

* fix lint

* fix audit

* add audit-ci.json

* update

* update

* update

* fix unit test

* linter

* fix import

* fix stub
  • Loading branch information
nitro-neal authored Jun 11, 2024
1 parent 2fc32ba commit 65b577b
Show file tree
Hide file tree
Showing 12 changed files with 590 additions and 249 deletions.
5 changes: 5 additions & 0 deletions .changeset/tender-bears-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web5/credentials": patch
---

Consuming latest web5 repos. Fixing diddht jwt verification
9 changes: 7 additions & 2 deletions .github/workflows/tests-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@ jobs:
steps:
- name: Checkout source
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
with:
submodules: true

# https://cashapp.github.io/hermit/usage/ci/
- name: Init Hermit
uses: cashapp/activate-hermit@v1
uses: cashapp/activate-hermit@31ce88b17a84941bb1b782f1b7b317856addf286 #v1.1.0
with:
cache: "true"

- name: Install dependencies
run: pnpm install --no-frozen-lockfile

- name: Report known vulnerabilities
run: pnpm audit
run: pnpm run audit-ci

test-with-node:
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions audit-ci.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
"moderate": true,
"allowlist": [
"ip",
"mysql2",
"braces",
"GHSA-rv95-896h-c2vc"
]
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"clean": "pnpm npkill -d $(pwd)/packages -t dist && pnpm npkill -d $(pwd) -t node_modules",
"build": "pnpm --recursive --stream build",
"dwn-server": "DWN_SERVER_PACKAGE_JSON=node_modules/@web5/dwn-server/package.json node node_modules/@web5/dwn-server/dist/esm/src/main.js || true",
"test:node": "pnpm --recursive test:node"
"test:node": "pnpm --recursive test:node",
"audit-ci": "audit-ci --config ./audit-ci.json"
},
"repository": {
"type": "git",
Expand All @@ -27,10 +28,11 @@
"license": "Apache-2.0",
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.27.1",
"@changesets/cli": "^2.27.5",
"@npmcli/package-json": "5.0.0",
"@typescript-eslint/eslint-plugin": "7.9.0",
"@web5/dwn-server": "0.2.3",
"audit-ci": "^7.0.1",
"eslint-plugin-mocha": "10.4.3",
"npkill": "0.11.3"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/credentials/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@
},
"dependencies": {
"@sphereon/pex": "2.1.0",
"@web5/common": "1.0.0",
"@web5/crypto": "1.0.0",
"@web5/dids": "1.0.3",
"@web5/common": "1.0.1",
"@web5/crypto": "1.0.1",
"@web5/dids": "1.1.0",
"pako": "^2.1.0"
},
"devDependencies": {
Expand Down
98 changes: 97 additions & 1 deletion packages/credentials/tests/jwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import type { JwtHeaderParams, JwtPayload, PrivateKeyJwk } from '@web5/crypto';
import { expect } from 'chai';
import { Convert } from '@web5/common';
import { Ed25519 } from '@web5/crypto';
import { DidJwk, DidKey, PortableDid } from '@web5/dids';
import { DidDereferencingResult, DidDht, DidJwk, DidKey, PortableDid } from '@web5/dids';

import { Jwt } from '../src/jwt.js';
import JwtVerifyTestVector from '../../../web5-spec/test-vectors/vc_jwt/verify.json' assert { type: 'json' };
import JwtDecodeTestVector from '../../../web5-spec/test-vectors/vc_jwt/decode.json' assert { type: 'json' };
import { VerifiableCredential } from '../src/verifiable-credential.js';
import sinon from 'sinon';

describe('Jwt', () => {
describe('parse()', () => {
Expand Down Expand Up @@ -72,6 +73,101 @@ describe('Jwt', () => {
});

describe('verify()', () => {
it('successful verify with did:dht', async () => {
const dereferenceStub = sinon.stub(Jwt.didResolver, 'dereference');

const mockResult: DidDereferencingResult = {
dereferencingMetadata: {
contentType: 'application/did+json'
},
contentStream: {
id : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0',
type : 'JsonWebKey',
controller : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo',
publicKeyJwk : {
kty : 'OKP',
crv : 'Ed25519',
x : 'VYKm2SCIV9Vz3BRy-v5R9GHz3EOJCPvZ1_gP1e3XiB0',
kid : 'cyvOypa6k-4ffsRWcza37s5XVOh1kO9ICUeo1ZxHVM8',
alg : 'EdDSA'
}
},
contentMetadata: {}
};

dereferenceStub.resolves(mockResult);

let portableDid : PortableDid = {
uri : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo',
document : {
id : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo',
verificationMethod : [
{
id : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0',
type : 'JsonWebKey',
controller : 'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo',
publicKeyJwk : {
crv : 'Ed25519',
kty : 'OKP',
x : 'VYKm2SCIV9Vz3BRy-v5R9GHz3EOJCPvZ1_gP1e3XiB0',
kid : 'cyvOypa6k-4ffsRWcza37s5XVOh1kO9ICUeo1ZxHVM8',
alg : 'EdDSA'
},
},
],
authentication: [
'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0'
],
assertionMethod: [
'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0'
],
capabilityDelegation: [
'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0'
],
capabilityInvocation: [
'did:dht:ksbkpsjytbm7kh6hnt3xi91t6to98zndtrrxzsqz9y87m5qztyqo#0'
],
},
metadata: {
types: [6, 7]
},
privateKeys: [
{
crv : 'Ed25519',
d : 'hdSIwbQwVD-fNOVEgt-k3mMl44Ip1iPi58Ex6VDGxqY',
kty : 'OKP',
x : 'VYKm2SCIV9Vz3BRy-v5R9GHz3EOJCPvZ1_gP1e3XiB0',
kid : 'cyvOypa6k-4ffsRWcza37s5XVOh1kO9ICUeo1ZxHVM8',
alg : 'EdDSA',
}
]
};

const bearerDid = await DidDht.import({ portableDid });

const siopv2Response = {
id_token: await Jwt.sign({
signerDid : bearerDid,
payload : {
iss : bearerDid.uri,
sub : bearerDid.uri,
aud : 'did:dht:ho3axp5pgp4k8a7kqtb8knn5uaqwy9ghkm98wrytnh67bsn7ezry',
nonce : 'd844f80d21c33ea6e087afa2b84dc31f',
iat : Math.floor(Date.now() / 1000),
exp : Math.floor(Date.now() / 1000) + (30 * 60), // plus 30 minutes
}
})
};

// Verify the JWT and make sure we get a result that it does not throw an error.
const jwtVerifyResult = await Jwt.verify({ jwt: siopv2Response.id_token });

expect(bearerDid.document?.verificationMethod?.[0]?.publicKeyJwk?.alg).to.equal('EdDSA');
expect(jwtVerifyResult.header.alg).to.equal('EdDSA');

dereferenceStub.restore();
});

it('throws error if JWT is expired', async () => {
const did = await DidKey.create({ options: { algorithm: 'secp256k1'} });
const header: JwtHeaderParams = { typ: 'JWT', alg: 'ES256K', kid: did.document.verificationMethod![0].id };
Expand Down
9 changes: 7 additions & 2 deletions packages/dids/src/methods/did-dht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ const AlgorithmToKeyTypeMap = {
* Private helper that maps did dht registered key types to their corresponding default algorithm identifiers.
*/
const KeyTypeToDefaultAlgorithmMap = {
[DidDhtRegisteredKeyType.Ed25519] : 'Ed25519',
[DidDhtRegisteredKeyType.Ed25519] : 'EdDSA',
[DidDhtRegisteredKeyType.secp256k1] : 'ES256K',
[DidDhtRegisteredKeyType.secp256r1] : 'ES256',
[DidDhtRegisteredKeyType.X25519] : 'ECDH-ES+A256KW',
Expand Down Expand Up @@ -1055,6 +1055,12 @@ export class DidDhtDocument {

publicKey.alg = parsedAlg || KeyTypeToDefaultAlgorithmMap[Number(t) as DidDhtRegisteredKeyType];

// TOOD: when this is complete https://github.com/TBD54566975/web5-js/issues/638 then we can add this back and
// update the test vectors kid back to '0'
// if(dnsRecordId === 'k0') {
// publicKey.kid = '0';
// }

// Determine the Verification Method ID: '0' for the identity key,
// the id from the TXT Data Object, or the JWK thumbprint if an explicity Verification Method ID not defined.
const vmId = dnsRecordId === 'k0' ? '0' : id !== undefined ? id : await computeJwkThumbprint({ jwk: publicKey });
Expand Down Expand Up @@ -1239,7 +1245,6 @@ export class DidDhtDocument {
if (methodId !== '0' && await computeJwkThumbprint({ jwk: publicKey }) !== methodId) {
txtData.unshift(`id=${methodId}`);
}

// Only set the algorithm property (`a`) if it differs from the default algorithm for the key type.
if(publicKey.alg !== KeyTypeToDefaultAlgorithmMap[keyType]) {
txtData.push(`a=${publicKey.alg}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"type": "JsonWebKey",
"controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
"publicKeyJwk": {
"kid": "0",
"alg": "Ed25519",
"kid": "HP6bkG6mv-YPsU3Vi5Coi5wGYSVW9abFBwBSQwLQ7PU",
"alg": "EdDSA",
"crv": "Ed25519",
"kty": "OKP",
"x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"type": "JsonWebKey",
"controller": "did:dht:cyuoqaf7itop8ohww4yn5ojg13qaq83r9zihgqntc5i9zwrfdfoo",
"publicKeyJwk": {
"kid": "0",
"alg": "Ed25519",
"kid": "HP6bkG6mv-YPsU3Vi5Coi5wGYSVW9abFBwBSQwLQ7PU",
"alg": "EdDSA",
"crv": "Ed25519",
"kty": "OKP",
"x": "YCcHYL2sYNPDlKaALcEmll2HHyT968M4UWbr-9CFGWE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"type": "JsonWebKey",
"controller": "did:dht:sr6jgmcc84xig18ix66qbiwnzeiumocaaybh13f5w97bfzus4pcy",
"publicKeyJwk": {
"kid": "0",
"alg": "Ed25519",
"kid": "TchFveGbbRf58hDDchTr_TAJ7XnWSrrGf8DK4rzG4nE",
"alg": "EdDSA",
"crv": "Ed25519",
"kty": "OKP",
"x": "sTyTLYw-n1NI9X-84NaCuis1wZjAA8lku6f6Et5201g"
Expand Down
15 changes: 3 additions & 12 deletions packages/dids/tests/methods/did-dht.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1295,10 +1295,7 @@ describe('DidDhtUtils', () => {

// vectors come from https://did-dht.com/#test-vectors
describe('Official DID:DHT Vector tests', () => {
// Temporarily disabling due to inability to add a custom `kid` to our JWK in the current deployment.
// We disable the test instead of changing the official specd test vector.
// TODO: https://github.com/TBD54566975/web5-js/issues/638
xit('vector 1', async () => {
it('vector 1', async () => {
const inputDidDocument = officialTestVector1.didDocument as DidDocument;
const dnsPacket = await DidDhtDocument.toDnsPacket({
didDocument : inputDidDocument,
Expand All @@ -1318,10 +1315,7 @@ describe('Official DID:DHT Vector tests', () => {
expect(didResolutionResult.didDocument).to.deep.equal(inputDidDocument);
});

// Temporarily disabling due to inability to add a custom `kid` to our JWK in the current deployment.
// We disable the test instead of changing the official specd test vector.
// TODO: https://github.com/TBD54566975/web5-js/issues/638
xit('vector 2', async () => {
it('vector 2', async () => {
const inputDidDocument = officialTestVector2.didDocument as DidDocument;
const dnsPacket = await DidDhtDocument.toDnsPacket({
didDocument : inputDidDocument,
Expand All @@ -1345,10 +1339,7 @@ describe('Official DID:DHT Vector tests', () => {
expect(didResolutionResult.didDocument).to.deep.equal(inputDidDocument);
});

// Temporarily disabling due to inability to add a custom `kid` to our JWK in the current deployment.
// We disable the test instead of changing the official specd test vector.
// TODO: https://github.com/TBD54566975/web5-js/issues/638
xit('vector 3', async () => {
it('vector 3', async () => {
const inputDidDocument = officialTestVector3.didDocument as DidDocument;
const dnsPacket = await DidDhtDocument.toDnsPacket({
didDocument : inputDidDocument,
Expand Down
Loading

0 comments on commit 65b577b

Please sign in to comment.