Skip to content

Commit

Permalink
Removed unnecessary isValidUrl condition check from audience para…
Browse files Browse the repository at this point in the history
…meter in `presentVCSDJWT` method (#29)

Co-authored-by: Vijay Shiyani <[email protected]>
  • Loading branch information
vijayshiyani and Vijay Shiyani authored May 15, 2024
1 parent 6597f85 commit 6111a0b
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 42 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project (loosely) adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 1.2.2 - 2024-05-15

### Fixed

- Removed unnecessary `isValidUrl` condition check from `audience` parameter in `presentVCSDJWT` method

## 1.2.1 - 2024-03-13

### Fixed
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@meeco/sd-jwt-vc",
"version": "1.2.1",
"version": "1.2.2",
"description": "SD-JWT VC implementation in typescript",
"scripts": {
"build": "tsc",
Expand Down
104 changes: 67 additions & 37 deletions src/holder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,47 +105,31 @@ describe('Holder', () => {
});

it('should present VerifiableCredential SD JWT With KeyBindingJWT', async () => {
const _publicJwk = {
kty: 'EC',
x: 'rH7OlmHqdpNOR2P28S7uroxAGk1321Nsgxgp4x_Piew',
y: 'WGCOJmA7nTsXP9Az_mtNy0jT7mdMCmStTfSO4DjRsSg',
crv: 'P-256',
};
const privateKey = {
kty: 'EC',
x: 'rH7OlmHqdpNOR2P28S7uroxAGk1321Nsgxgp4x_Piew',
y: 'WGCOJmA7nTsXP9Az_mtNy0jT7mdMCmStTfSO4DjRsSg',
crv: 'P-256',
d: '9Ie2xvzUdQBGCjT9ktsZYGzwG4hOWea-zvCQSQSWJxk',
};

const pk = await importJWK(privateKey);
const audience = 'https://valid.verifier.url';
const { disclosures, keyBindingJWT, disclosedList, nonceFromVerifier } =
await presentVCSDWithKeyBindingJWT(audience);

const signer: SignerConfig = {
alg: supportedAlgorithm.ES256,
callback: signerCallbackFn(pk),
};
const holder = new Holder(signer, testHasherFn);
const issuedSDJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~WyJJbFl3RkV5WDlLSFVIU1NFIiwiYWdlIiwyNV0~';
expect(disclosures[0].key).toEqual(disclosedList[0].key);
expect(disclosures[0].value).toEqual(disclosedList[0].value);
expect(keyBindingJWT).toBeDefined();
expect(typeof keyBindingJWT).toBe('string');

const disclosedList = [
{
disclosure: 'WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0',
key: 'name',
value: 'test person',
},
];
// decode keyBindingJWT with decodeJWT
const { header, payload, signature } = decodeJWT(keyBindingJWT);
expect(header.alg).toEqual(supportedAlgorithm.ES256);
expect(header.typ).toEqual(SD_KEY_BINDING_JWT_TYP);

const nonceFromVerifier = 'nIdBbNgRqCXBl8YOkfVdg==';
expect(payload.aud).toEqual(audience);
expect(payload.nonce).toEqual(nonceFromVerifier);
expect(payload.sd_hash).toBeDefined();

const { vcSDJWTWithkeyBindingJWT } = await holder.presentVCSDJWT(issuedSDJWT, disclosedList, {
nonce: nonceFromVerifier,
audience: 'https://valid.verifier.url',
keyBindingVerifyCallbackFn: keyBindingVerifierCallbackFn(),
});
expect(signature).toBeDefined();
});

const { disclosures, keyBindingJWT } = decodeSDJWT(vcSDJWTWithkeyBindingJWT);
it('should allow to present VC SD JWT with KeyBindingJWT when AUD is not valid URL', async () => {
const audience = 'verifier.ssi.tir.budru.de';
const { disclosures, keyBindingJWT, disclosedList, nonceFromVerifier } =
await presentVCSDWithKeyBindingJWT(audience);

expect(disclosures[0].key).toEqual(disclosedList[0].key);
expect(disclosures[0].value).toEqual(disclosedList[0].value);
Expand All @@ -157,7 +141,7 @@ describe('Holder', () => {
expect(header.alg).toEqual(supportedAlgorithm.ES256);
expect(header.typ).toEqual(SD_KEY_BINDING_JWT_TYP);

expect(payload.aud).toEqual('https://valid.verifier.url');
expect(payload.aud).toEqual(audience);
expect(payload.nonce).toEqual(nonceFromVerifier);
expect(payload.sd_hash).toBeDefined();

Expand Down Expand Up @@ -204,4 +188,50 @@ describe('Holder', () => {
expect(result).toEqual(expected);
});
});

//helper function
async function presentVCSDWithKeyBindingJWT(audience: string) {
const _publicJwk = {
kty: 'EC',
x: 'rH7OlmHqdpNOR2P28S7uroxAGk1321Nsgxgp4x_Piew',
y: 'WGCOJmA7nTsXP9Az_mtNy0jT7mdMCmStTfSO4DjRsSg',
crv: 'P-256',
};
const privateKey = {
kty: 'EC',
x: 'rH7OlmHqdpNOR2P28S7uroxAGk1321Nsgxgp4x_Piew',
y: 'WGCOJmA7nTsXP9Az_mtNy0jT7mdMCmStTfSO4DjRsSg',
crv: 'P-256',
d: '9Ie2xvzUdQBGCjT9ktsZYGzwG4hOWea-zvCQSQSWJxk',
};

const pk = await importJWK(privateKey);

const signer: SignerConfig = {
alg: supportedAlgorithm.ES256,
callback: signerCallbackFn(pk),
};
const holder = new Holder(signer, testHasherFn);
const issuedSDJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~WyJJbFl3RkV5WDlLSFVIU1NFIiwiYWdlIiwyNV0~';
const disclosedList = [
{
disclosure: 'WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0',
key: 'name',
value: 'test person',
},
];

const nonceFromVerifier = 'nIdBbNgRqCXBl8YOkfVdg==';

const { vcSDJWTWithkeyBindingJWT } = await holder.presentVCSDJWT(issuedSDJWT, disclosedList, {
nonce: nonceFromVerifier,
audience: audience,
keyBindingVerifyCallbackFn: keyBindingVerifierCallbackFn(),
});

const { disclosures, keyBindingJWT } = decodeSDJWT(vcSDJWTWithkeyBindingJWT);

return { disclosures, keyBindingJWT, disclosedList, nonceFromVerifier };
}
});
4 changes: 2 additions & 2 deletions src/holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
SD_KEY_BINDING_JWT_TYP,
SignerConfig,
} from './types.js';
import { defaultHashAlgorithm, isValidUrl } from './util.js';
import { defaultHashAlgorithm } from './util.js';

export class Holder {
private signer: SignerConfig;
Expand Down Expand Up @@ -118,7 +118,7 @@ export class Holder {
kbJWTHeader?: Omit<JWTHeaderParameters, 'typ' | 'alg'>;
},
): Promise<{ vcSDJWTWithkeyBindingJWT: JWT; nonce?: string }> {
if (options.audience && (typeof options.audience !== 'string' || !isValidUrl(options.audience))) {
if (options.audience && typeof options.audience !== 'string') {
throw new SDJWTVCError('Invalid audience parameter');
}

Expand Down

0 comments on commit 6111a0b

Please sign in to comment.