Skip to content

Commit

Permalink
updates to latest did and crypto package
Browse files Browse the repository at this point in the history
  • Loading branch information
nitro-neal committed Feb 12, 2024
1 parent aacb0bc commit 894f0b9
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 148 deletions.
63 changes: 3 additions & 60 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions packages/credentials/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@
},
"dependencies": {
"@sphereon/pex": "2.1.0",
"@web5/common": "0.2.2",
"@web5/crypto": "0.2.4",
"@web5/dids": "0.3.0"
"@web5/common": "0.2.3",
"@web5/crypto": "0.4.0",
"@web5/dids": "0.4.0"
},
"devDependencies": {
"@playwright/test": "1.40.1",
Expand Down
57 changes: 18 additions & 39 deletions packages/credentials/src/jwt.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { BearerDid } from '@web5/dids';
import { BearerDid } from '@web5/dids';
import type {
JwtPayload,
Web5Crypto,
CryptoAlgorithm,
JwtHeaderParams,
JwkParamsEcPublic,
JwkParamsOkpPublic,
CryptoAlgorithm,
} from '@web5/crypto';

import { Convert } from '@web5/common';
Expand Down Expand Up @@ -62,25 +61,23 @@ export type VerifyJwtOptions = {
* Represents a signer with a specific cryptographic algorithm and options.
* @template T - The type of cryptographic options.
*/
type Signer<T extends Web5Crypto.Algorithm> = {
signer: CryptoAlgorithm,
type Signer<T extends CryptoAlgorithm> = {
signer: EcdsaAlgorithm | EdDsaAlgorithm,
options?: T | undefined
alg: string
crv: string
}

const secp256k1Signer: Signer<Web5Crypto.EcdsaOptions> = {
signer : new EcdsaAlgorithm(),
options : { name: 'ES256K'},
alg : 'ES256K',
crv : 'secp256k1'
const secp256k1Signer: Signer<EcdsaAlgorithm> = {
signer : new EcdsaAlgorithm(),
alg : 'ES256K',
crv : 'secp256k1'
};

const ed25519Signer: Signer<Web5Crypto.EdDsaOptions> = {
signer : new EdDsaAlgorithm(),
options : { name: 'EdDSA' },
alg : 'EdDSA',
crv : 'Ed25519'
const ed25519Signer: Signer<EdDsaAlgorithm> = {
signer : new EdDsaAlgorithm(),
alg : 'EdDSA',
crv : 'Ed25519'
};

/**
Expand All @@ -90,7 +87,7 @@ const ed25519Signer: Signer<Web5Crypto.EdDsaOptions> = {
*/
export class Jwt {
/** supported cryptographic algorithms. keys are `${alg}:${crv}`. */
static algorithms: { [alg: string]: Signer<Web5Crypto.EcdsaOptions | Web5Crypto.EdDsaOptions> } = {
static algorithms: { [alg: string]: Signer<EcdsaAlgorithm | EdDsaAlgorithm> } = {
'ES256K:' : secp256k1Signer,
'ES256K:secp256k1' : secp256k1Signer,
':secp256k1' : secp256k1Signer,
Expand All @@ -115,31 +112,16 @@ export class Jwt {
*/
static async sign(options: SignJwtOptions): Promise<string> {
const { signerDid, payload } = options;
const signer = await signerDid.getSigner();

let vmId = signerDid.didDocument.verificationMethod![0].id!;
let vmId = signer.keyId;
if (vmId.charAt(0) === '#') {
vmId = `${signerDid.uri}${vmId}`;
}

// TODO: Change once signer has a method to get the alg and kid
// const header = {
// typ : 'JWT',
// alg: signer.alg,
// kid: signer.kid
// }

let alg;
if(signerDid.didDocument.verificationMethod![0].publicKeyJwk?.crv === 'Ed25519') {
alg = 'EdDSA';
} else if(signerDid.didDocument.verificationMethod![0].publicKeyJwk?.crv === 'secp256k1'){
alg = 'ES256K';
} else {
throw new Error(`Signing failed: alg not supported`);
}

const header: JwtHeaderParams = {
typ : 'JWT',
alg : alg!,
alg : signer.algorithm,
kid : vmId,
};

Expand All @@ -149,8 +131,6 @@ export class Jwt {
const toSign = `${base64UrlEncodedHeader}.${base64UrlEncodedPayload}`;
const toSignBytes = Convert.string(toSign).toUint8Array();

const signer = await signerDid.getSigner();

const signatureBytes = await signer.sign({data: toSignBytes});

const base64UrlEncodedSignature = Convert.uint8Array(signatureBytes).toBase64Url();
Expand Down Expand Up @@ -203,13 +183,12 @@ export class Jwt {
throw new Error(`Verification failed: ${algorithmId} not supported`);
}

const { signer, options: signatureAlgorithm } = Jwt.algorithms[algorithmId];
const { signer } = Jwt.algorithms[algorithmId];

const isSignatureValid = await signer.verify({
algorithm : signatureAlgorithm!,
key : publicKeyJwk,
signature : signatureBytes,
data : signedDataBytes,
signature : signatureBytes
});

if (!isSignatureValid) {
Expand Down
49 changes: 32 additions & 17 deletions packages/credentials/tests/jwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('Jwt', () => {
describe('verify()', () => {
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.didDocument.verificationMethod![0].id };
const header: JwtHeaderParams = { typ: 'JWT', alg: 'ES256K', kid: did.document.verificationMethod![0].id };
const base64UrlEncodedHeader = Convert.object(header).toBase64Url();

const payload: JwtPayload = { exp: Math.floor(Date.now() / 1000 - 1) };
Expand Down Expand Up @@ -102,7 +102,7 @@ describe('Jwt', () => {

it('throws error if alg is not supported', async () => {
const did = await DidKey.create({ options: { algorithm: 'secp256k1'} });
const header: JwtHeaderParams = { typ: 'JWT', alg: 'RS256', kid: did.didDocument.verificationMethod![0].id };
const header: JwtHeaderParams = { typ: 'JWT', alg: 'RS256', kid: did.document.verificationMethod![0].id };
const base64UrlEncodedHeader = Convert.object(header).toBase64Url();

const payload: JwtPayload = { iat: Math.floor(Date.now() / 1000) };
Expand All @@ -117,27 +117,42 @@ describe('Jwt', () => {
});

it('returns signer DID if verification succeeds', async () => {
const portabldDid: PortableDid = {
uri : 'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN',
verificationMethods : [{
publicKeyJwk: {
kty : 'OKP',
crv : 'Ed25519',
x : 'VnSOQ-n7kRcYd0XGW2MNCv7DDY5py5XhNcjM7-Y1HVM'
},
privateKeyJwk: {
const portableDid: PortableDid = {
uri : 'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN',
document : {
'@context' : 'https://www.w3.org/ns/did/v1',
id : 'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN',
verificationMethod : [
{
id : 'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN#z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN', // You may need to adjust the ID based on your requirements
type : 'JsonWebKey2020', // Adjust the type according to your needs, assuming JsonWebKey2020
controller : 'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN',
publicKeyJwk : {
kty : 'OKP',
crv : 'Ed25519',
x : 'VnSOQ-n7kRcYd0XGW2MNCv7DDY5py5XhNcjM7-Y1HVM',
},
},
],
authentication: [
'did:key:z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN#z6MkkGkByH7rSY3uxDEPTk1CZzPG5hvf564ABFLQzCFwyYNN',
],
// Add other fields like assertionMethod, capabilityInvocation, etc., as needed
},
metadata : {}, // Populate according to DidMetadata interface
privateKeys : [
{
kty : 'OKP',
crv : 'Ed25519',
x : 'VnSOQ-n7kRcYd0XGW2MNCv7DDY5py5XhNcjM7-Y1HVM',
d : 'iTD5DIOKZNkwgzsND-I8CLIXmgTxfQ1HUzl9fpMktAo'
d : 'iTD5DIOKZNkwgzsND-I8CLIXmgTxfQ1HUzl9fpMktAo',
},
purposes: ['authentication']
}]
],
};

const did = await DidKey.fromKeys(portabldDid);
const did = await DidKey.import({ portableDid });

const header: JwtHeaderParams = { typ: 'JWT', alg: 'EdDSA', kid: did.didDocument.verificationMethod![0].id };
const header: JwtHeaderParams = { typ: 'JWT', alg: 'EdDSA', kid: did.document.verificationMethod![0].id };
const base64UrlEncodedHeader = Convert.object(header).toBase64Url();

const payload: JwtPayload = { iat: Math.floor(Date.now() / 1000) };
Expand All @@ -146,7 +161,7 @@ describe('Jwt', () => {
const toSign = `${base64UrlEncodedHeader}.${base64UrlEncodedPayload}`;
const toSignBytes = Convert.string(toSign).toUint8Array();

const privateKeyJwk = portabldDid.verificationMethods![0].privateKeyJwk;
const privateKeyJwk = portableDid.privateKeys![0];

const signatureBytes = await Ed25519.sign({ key: privateKeyJwk as PrivateKeyJwk, data: toSignBytes });
const base64UrlEncodedSignature = Convert.uint8Array(signatureBytes).toBase64Url();
Expand Down
Loading

0 comments on commit 894f0b9

Please sign in to comment.