Skip to content

Commit

Permalink
Feature/add kb jwt header (#26)
Browse files Browse the repository at this point in the history
Add kb+jwt header when creating Key Binding JWT
  • Loading branch information
ragnika authored Feb 19, 2024
1 parent dc84e84 commit eab5f61
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 41 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ 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.1.0 - 2024-02-19

### Added

- Add parameters to allow adding params to kbjwt header

### Changed

- renamed `revealDisclosure` to `selectDisclosure` in `PresentVCSDJWT` to better reflect the intent of the function

## 1.0.4 - 2024-02-14

### Fixed
Expand All @@ -13,7 +23,7 @@ and this project (loosely) adheres to [Semantic Versioning](https://semver.org/s

## 1.0.3 - 2024-02-14

### Added
### Added

- Add fallback to `GET /.well-known/jwt-issuer` in case `GET /.well-known/jwt-vc-issuer` returns error

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ const hasherFnResolver = (alg: string) => {
const hasher = (data: string): string => {
const digest = createHash(alg).update(data).digest();
return base64encode(digest);
}
};

return Promise.resolve(hasher);
}
};

const signerCallbackFn = function (privateKey: Uint8Array | KeyLike): Signer {
return (protectedHeader: JWTHeaderParameters, payload: JWTPayload): Promise<string> => {
Expand Down Expand Up @@ -203,16 +203,17 @@ async function main() {
const issuedSDJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~WyJJbFl3RkV5WDlLSFVIU1NFIiwiYWdlIiwyNV0~';

const disclosedList = [
const disclosureList = [
{
key: 'name',
value: 'test person',
disclosure: 'WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0',
},
];

const nonceFromVerifier = 'nIdBbNgRqCXBl8YOkfVdg==';

const { vcSDJWTWithkeyBindingJWT } = await holder.presentVCSDJWT(issuedSDJWT, disclosedList, {
const { vcSDJWTWithkeyBindingJWT } = await holder.presentVCSDJWT(issuedSDJWT, disclosureList, {
nonce: nonceFromVerifier,
audience: 'https://valid.verifier.url',
keyBindingVerifyCallbackFn: keyBindingVerifierCallbackFn(),
Expand Down Expand Up @@ -302,7 +303,7 @@ async function main() {
kty: 'OKP',
});

const vcSDJWTWithoutKeyBinding: string = vcSDJWTWithkeyBindingJWT.slice(
const vcSDJWTWithoutKeyBinding: string = vcSDJWTWithkeyBindingJWT.slice(
0,
vcSDJWTWithkeyBindingJWT.lastIndexOf('~') + 1,
);
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.0.4",
"version": "1.1.0",
"description": "SD-JWT VC implementation in typescript",
"scripts": {
"build": "tsc",
Expand Down
74 changes: 61 additions & 13 deletions src/holder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { decodeJWT, decodeSDJWT } from '@meeco/sd-jwt';
import { generateKeyPair, importJWK } from 'jose';
import { Holder } from './holder';
import { hasherCallbackFn, keyBindingVerifierCallbackFn, signerCallbackFn } from './test-utils/helpers';
import { SignerConfig } from './types';
import { defaultHashAlgorithm, supportedAlgorithm } from './util';
import { SD_KEY_BINDING_JWT_TYP, SignerConfig } from './types';
import { supportedAlgorithm } from './util';

describe('Holder', () => {
let holder: Holder;
Expand Down Expand Up @@ -50,10 +50,58 @@ describe('Holder', () => {

it('should get KeyBindingJWT', async () => {
const nonce = 'nIdBbNgRqCXBl8YOkfVdg==';
const { keyBindingJWT } = await holder.getKeyBindingJWT('https://valid.verifier.url', nonce, defaultHashAlgorithm);
const verifierURL = 'https://valid.verifier.url';
const sdHash = 'disclosureDigest';

const { keyBindingJWT } = await holder.getKeyBindingJWT(verifierURL, nonce, sdHash);

expect(keyBindingJWT).toBeDefined();
expect(typeof keyBindingJWT).toBe('string');

const decodedJWT = decodeJWT(keyBindingJWT);

expect(decodedJWT.header).toEqual({
alg: supportedAlgorithm.ES256,
typ: SD_KEY_BINDING_JWT_TYP,
});

expect(decodedJWT.payload).toEqual({
aud: verifierURL,
iat: expect.any(Number),
nonce: nonce,
sd_hash: sdHash,
});
});

it('should get KeyBindingJWT with additional header params', async () => {
const nonce = 'nIdBbNgRqCXBl8YOkfVdg==';
const verifierURL = 'https://valid.verifier.url';
const sdHash = 'disclosureDigest';
const header = {
kid: '1b94c',
x5c: [
'MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB...',
'MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJC...',
],
};

const { keyBindingJWT } = await holder.getKeyBindingJWT(verifierURL, nonce, sdHash, header);

expect(keyBindingJWT).toBeDefined();

const decodedJWT = decodeJWT(keyBindingJWT);

expect(decodedJWT.header).toEqual({
...header,
alg: supportedAlgorithm.ES256,
typ: SD_KEY_BINDING_JWT_TYP,
});

expect(decodedJWT.payload).toEqual({
aud: verifierURL,
iat: expect.any(Number),
nonce: nonce,
sd_hash: sdHash,
});
});

it('should present VerifiableCredential SD JWT With KeyBindingJWT', async () => {
Expand Down Expand Up @@ -107,7 +155,7 @@ describe('Holder', () => {
// decode keyBindingJWT with decodeJWT
const { header, payload, signature } = decodeJWT(keyBindingJWT);
expect(header.alg).toEqual(supportedAlgorithm.ES256);
expect(header.typ).toEqual(Holder.SD_KEY_BINDING_JWT_TYP);
expect(header.typ).toEqual(SD_KEY_BINDING_JWT_TYP);

expect(payload.aud).toEqual('https://valid.verifier.url');
expect(payload.nonce).toEqual(nonceFromVerifier);
Expand All @@ -116,11 +164,11 @@ describe('Holder', () => {
expect(signature).toBeDefined();
});

describe('revealDisclosures', () => {
it('should reveal disclosed information that matches the disclosed list', () => {
describe('selectDisclosures', () => {
it('should select disclosed information that matches the disclosures list', () => {
const sdJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~WyJJbFl3RkV5WDlLSFVIU1NFIiwiYWdlIiwyNV0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZhbGlkLnZlcmlmaWVyLnVybCIsIm5vbmNlIjoibklkQmJOZWdScUNYQmw4WU9rZlZkZz09IiwiaWF0IjoxNjk1NzgzOTgzMDQxfQ.YwgHkYEpCFRHny5L4KdnU_qARVHL2jAScodRqfF5UP50nbryqIl4i1OuaxuQKala_uYNT-e0D4xzghoxWE56SQ';
const disclosedList = [
const disclosuresList = [
{
disclosure: 'WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0',
key: 'name',
Expand All @@ -129,30 +177,30 @@ describe('Holder', () => {
];
const expected =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~';
const result = holder.revealDisclosures(sdJWT, disclosedList);
const result = holder.selectDisclosures(sdJWT, disclosuresList);
expect(result).toEqual(expected);
});

it('should throw an error if SD-JWT do not have disclosures', () => {
const sdJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA';
const disclosedList = [
const disclosuresList = [
{
disclosure: 'WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0',
key: 'name',
value: 'test person',
},
];
expect(() => holder.revealDisclosures(sdJWT, disclosedList)).toThrow('No disclosures in SD-JWT');
expect(() => holder.selectDisclosures(sdJWT, disclosuresList)).toThrow('No disclosures in SD-JWT');
});

it('should exclude all disclosures', () => {
const sdJWT =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~WyJNcEFKRDhBWVBQaEJhT0tNIiwibmFtZSIsInRlc3QgcGVyc29uIl0~WyJJbFl3RkV5WDlLSFVIU1NFIiwiYWdlIiwyNV0~eyJ0eXAiOiJrYitqd3QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3ZhbGlkLnZlcmlmaWVyLnVybCIsIm5vbmNlIjoibklkQmJOZWdScUNYQmw4WU9rZlZkZz09IiwiaWF0IjoxNjk1NzgzOTgzMDQxfQ.YwgHkYEpCFRHny5L4KdnU_qARVHL2jAScodRqfF5UP50nbryqIl4i1OuaxuQKala_uYNT-e0D4xzghoxWE56SQ';
const disclosedList = [];
const disclosuresList = [];
const expected =
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSJ9.eyJpYXQiOjE2OTU2ODI0MDg4NTcsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJ4Ijoickg3T2xtSHFkcE5PUjJQMjhTN3Vyb3hBR2sxMzIxTnNneGdwNHhfUGlldyIsInkiOiJXR0NPSm1BN25Uc1hQOUF6X210TnkwalQ3bWRNQ21TdFRmU080RGpSc1NnIiwiY3J2IjoiUC0yNTYifX0sImlzcyI6Imh0dHBzOi8vdmFsaWQuaXNzdWVyLnVybCIsInR5cGUiOiJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsInN0YXR1cyI6eyJpZHgiOiJzdGF0dXNJbmRleCIsInVyaSI6Imh0dHBzOi8vdmFsaWQuc3RhdHVzLnVybCJ9LCJwZXJzb24iOnsiX3NkIjpbImNRbzBUTTdfZEZXb2djcUpUTlJPeGJUTnI1T0VaakNWUHNlVVBVN0ROa3ciLCJZY3BHVTNKTDFvS0NoOXY4VjAwQmxWLTQtZTFWN1h0U1BvYUtra2RuZG1BIl19fQ.iPmq7Fv-pxS5NgTpH5xUarz6uG1MIphHy4q5mWdLBJRfp6ER2eG306WeHhCBoDzrYURgWZiEySnTEBDbD2HfCA~';
const result = holder.revealDisclosures(sdJWT, disclosedList);
const result = holder.selectDisclosures(sdJWT, disclosuresList);
expect(result).toEqual(expected);
});
});
Expand Down
58 changes: 39 additions & 19 deletions src/holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,28 @@ import {
GetHasher,
Hasher,
JWK,
JWTHeaderParameters,
KeyBindingVerifier,
base64encode,
decodeJWT,
decodeSDJWT,
} from '@meeco/sd-jwt';
import { SDJWTVCError } from './errors.js';
import { CreateSDJWTPayload, JWT, PresentSDJWTPayload, SD_JWT_FORMAT_SEPARATOR, SignerConfig } from './types.js';
import {
CreateSDJWTPayload,
JWT,
PresentSDJWTPayload,
SD_JWT_FORMAT_SEPARATOR,
SD_KEY_BINDING_JWT_TYP,
SignerConfig,
} from './types.js';
import { defaultHashAlgorithm, isValidUrl } from './util.js';

export class Holder {
private signer: SignerConfig;
private hasherFnResolver: GetHasher;

public static SD_KEY_BINDING_JWT_TYP = 'kb+jwt';
public static SD_KEY_BINDING_JWT_TYP = SD_KEY_BINDING_JWT_TYP;

/**
* Signer Config with callback function used for signing key binding JWT.
Expand Down Expand Up @@ -59,10 +67,12 @@ export class Holder {
audience: string,
nonce: string,
sdHash: string,
header?: Omit<JWTHeaderParameters, 'typ' | 'alg'>,
): Promise<{ keyBindingJWT: JWT; nonce?: string }> {
try {
const protectedHeader = {
typ: Holder.SD_KEY_BINDING_JWT_TYP,
...header,
typ: SD_KEY_BINDING_JWT_TYP,
alg: this.signer.alg,
};

Expand Down Expand Up @@ -101,7 +111,12 @@ export class Holder {
async presentVCSDJWT(
sdJWT: JWT,
disclosedList: Disclosure[],
options?: { nonce?: string; audience?: string; keyBindingVerifyCallbackFn?: KeyBindingVerifier },
options?: {
nonce?: string;
audience?: string;
keyBindingVerifyCallbackFn?: KeyBindingVerifier;
kbJWTHeader?: Omit<JWTHeaderParameters, 'typ' | 'alg'>;
},
): Promise<{ vcSDJWTWithkeyBindingJWT: JWT; nonce?: string }> {
if (options.audience && (typeof options.audience !== 'string' || !isValidUrl(options.audience))) {
throw new SDJWTVCError('Invalid audience parameter');
Expand All @@ -123,28 +138,33 @@ export class Holder {
const shHashingAlgorithm = (jwt.payload['_sd_alg'] as string) || defaultHashAlgorithm;
const hasher: Hasher = await this.getHasher(shHashingAlgorithm);

const vcSDJWTWithRevealedDisclosures = this.revealDisclosures(sdJWT, disclosedList);
const sdJwtHash: string = hasher(vcSDJWTWithRevealedDisclosures);
const vcSDJWTWithSelectedDisclosures = this.selectDisclosures(sdJWT, disclosedList);
const sdJwtHash: string = hasher(vcSDJWTWithSelectedDisclosures);

const { keyBindingJWT } = await this.getKeyBindingJWT(options.audience, options.nonce, sdJwtHash);
const { keyBindingJWT } = await this.getKeyBindingJWT(
options.audience,
options.nonce,
sdJwtHash,
options.kbJWTHeader,
);

if (options.keyBindingVerifyCallbackFn && typeof options.keyBindingVerifyCallbackFn === 'function') {
await this.verifyKeyBinding(options.keyBindingVerifyCallbackFn, keyBindingJWT, holderPublicKeyJWK);
}

const vcSDJWTWithkeyBindingJWT = `${vcSDJWTWithRevealedDisclosures}${keyBindingJWT}`;
const vcSDJWTWithkeyBindingJWT = `${vcSDJWTWithSelectedDisclosures}${keyBindingJWT}`;

return { vcSDJWTWithkeyBindingJWT: vcSDJWTWithkeyBindingJWT, nonce: options.nonce };
}

/**
* Reveals the disclosed claims in the VC SD-JWT.
* @param sdJWT The SD-JWT to reveal the claims in.
* @param disclosedList The list of disclosed claims.
* @throws An error if the disclosed claims cannot be revealed.
* Select the disclosed claims in the VC SD-JWT.
* @param sdJWT The compact SD-JWT.
* @param disclosuresList The list of disclosures to be added to the SD-JWT presentation.
* @throws An error if the disclosed claims cannot be selected.
* @returns The VC SD-JWT with the disclosed claims.
*/
revealDisclosures(sdJWT: JWT, disclosedList: Disclosure[]): JWT {
selectDisclosures(sdJWT: JWT, disclosuresList: Disclosure[]): JWT {
if (typeof sdJWT !== 'string' || !sdJWT.includes(SD_JWT_FORMAT_SEPARATOR)) {
throw new SDJWTVCError('No disclosures in SD-JWT');
}
Expand All @@ -157,23 +177,23 @@ export class Holder {

const compactJWT = sdJWT.split(SD_JWT_FORMAT_SEPARATOR)[0];

if (!disclosedList || disclosedList.length === 0) {
if (!disclosuresList || disclosuresList.length === 0) {
return `${compactJWT}${SD_JWT_FORMAT_SEPARATOR}`;
}

const revealedDisclosures = disclosures.filter((disclosure) => {
return disclosedList.some((disclosed) => disclosed.disclosure === disclosure.disclosure);
const selectedDisclosures = disclosures.filter((disclosure) => {
return disclosuresList.some((disclosed) => disclosed.disclosure === disclosure.disclosure);
});

if (revealedDisclosures.length === 0) {
if (selectedDisclosures.length === 0) {
return `${compactJWT}${SD_JWT_FORMAT_SEPARATOR}`;
}

const revealedDisclosuresEncoded = revealedDisclosures
const selectedDisclosuresEncoded = selectedDisclosures
.map((disclosure) => disclosure.disclosure)
.join(SD_JWT_FORMAT_SEPARATOR);

return `${compactJWT}${SD_JWT_FORMAT_SEPARATOR}${revealedDisclosuresEncoded}${SD_JWT_FORMAT_SEPARATOR}`;
return `${compactJWT}${SD_JWT_FORMAT_SEPARATOR}${selectedDisclosuresEncoded}${SD_JWT_FORMAT_SEPARATOR}`;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { supportedAlgorithm } from './util.js';

export const SD_JWT_FORMAT_SEPARATOR = '~';

export const SD_KEY_BINDING_JWT_TYP = 'kb+jwt';

export type JWT = string;

export interface Cnf {
Expand Down

0 comments on commit eab5f61

Please sign in to comment.