Skip to content

Commit

Permalink
Feat/type metadata (openwallet-foundation#247)
Browse files Browse the repository at this point in the history
feat: add type metadata fetching and validation via vct URL
Signed-off-by: Mirko Mollik <mirkomollik@gmail.com>
  • Loading branch information
cre8 authored Aug 18, 2024
1 parent c3f4580 commit 96e76a9
Show file tree
Hide file tree
Showing 22 changed files with 699 additions and 36 deletions.
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/custom_header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/decoy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
2 changes: 1 addition & 1 deletion examples/sd-jwt-vc-example/kb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { createSignerVerifier, digest, generateSalt } from './utils';
{
iss: 'Issuer',
iat: new Date().getTime(),
vct: 'https://example.com',
vct: 'ExampleCredentials',
...claims,
},
disclosureFrame,
Expand Down
7 changes: 5 additions & 2 deletions packages/browser-crypto/src/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ export const generateSalt = (length: number): string => {
};

export async function digest(
data: string,
data: string | ArrayBuffer,
algorithm = 'SHA-256',
): Promise<Uint8Array> {
const ec = new TextEncoder();
const digest = await window.crypto.subtle.digest(algorithm, ec.encode(data));
const digest = await window.crypto.subtle.digest(
algorithm,
typeof data === 'string' ? ec.encode(data) : data,
);
return new Uint8Array(digest);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
type PresentationFrame,
type SDJWTCompact,
type SDJWTConfig,
type JwtPayload,
} from '@sd-jwt/types';
import { getSDAlgAndPayload } from '@sd-jwt/decode';
import type { JwtPayload } from '@sd-jwt/types';

export * from './sdjwt';
export * from './kbjwt';
Expand All @@ -25,7 +25,7 @@ export class SDJwtInstance<ExtendedPayload extends SdJwtPayload> {
//header type
protected type?: string;

public static DEFAULT_hashAlg = 'sha-256';
public static readonly DEFAULT_hashAlg = 'sha-256';

protected userConfig: SDJWTConfig = {};

Expand Down
11 changes: 9 additions & 2 deletions packages/node-crypto/src/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ export const generateSalt = (length: number): string => {
return salt.substring(0, length);
};

export const digest = (data: string, algorithm = 'SHA-256'): Uint8Array => {
export const digest = (
data: string | ArrayBuffer,
algorithm = 'SHA-256',
): Uint8Array => {
const nodeAlg = toNodeCryptoAlg(algorithm);
const hash = createHash(nodeAlg);
hash.update(data);
if (typeof data === 'string') {
hash.update(data);
} else {
hash.update(Buffer.from(data));
}
const hashBuffer = hash.digest();
return new Uint8Array(hashBuffer);
};
Expand Down
20 changes: 20 additions & 0 deletions packages/sd-jwt-vc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,28 @@ const verified = await sdjwt.verify(presentation);
Check out more details in our [documentation](https://github.com/openwallet-foundation-labs/sd-jwt-js/tree/main/docs) or [examples](https://github.com/openwallet-foundation-labs/sd-jwt-js/tree/main/examples)

### Revocation

To add revocation capabilities, you can use the `@sd-jwt/jwt-status-list` library to create a JWT Status List and include it in the SD-JWT-VC.

### Type Metadata

By setting the `loadTypeMetadataFormat` to `true` like this:

```typescript
const sdjwt = new SDJwtVcInstance({
signer,
signAlg: 'EdDSA',
verifier,
hasher: digest,
hashAlg: 'SHA-256',
saltGenerator: generateSalt,
loadTypeMetadataFormat: true,
});
```

The library will load load the type metadata format based on the `vct` value according to the [SD-JWT-VC specification](https://www.ietf.org/archive/id/draft-ietf-oauth-sd-jwt-vc-04.html#name-type-metadata) and validate this schema.

Since at this point the display is not yet implemented, the library will only validate the schema and return the type metadata format. In the future the values of the type metadata can be fetched via a function call.

### Dependencies

Expand Down
9 changes: 6 additions & 3 deletions packages/sd-jwt-vc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"build": "rm -rf **/dist && tsup",
"lint": "biome lint ./src",
"test": "pnpm run test:node && pnpm run test:browser && pnpm run test:e2e && pnpm run test:cov",
"test:node": "vitest run ./src/test/*.spec.ts && vitest run ./src/test/*.spec.ts --environment jsdom",
"test:node": "vitest run ./src/test/*.spec.ts",
"test:browser": "vitest run ./src/test/*.spec.ts --environment jsdom",
"test:e2e": "vitest run ./test/*e2e.spec.ts --environment node",
"test:cov": "vitest run --coverage"
Expand All @@ -37,12 +37,15 @@
"dependencies": {
"@sd-jwt/core": "workspace:*",
"@sd-jwt/jwt-status-list": "workspace:*",
"@sd-jwt/utils": "workspace:*"
"@sd-jwt/utils": "workspace:*",
"ajv": "^8.17.1",
"ajv-formats": "^3.0.1"
},
"devDependencies": {
"@sd-jwt/crypto-nodejs": "workspace:*",
"@sd-jwt/types": "workspace:*",
"jose": "^5.2.2"
"jose": "^5.2.2",
"msw": "^2.3.5"
},
"publishConfig": {
"access": "public"
Expand Down
12 changes: 10 additions & 2 deletions packages/sd-jwt-vc/src/sd-jwt-vc-config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import type { SDJWTConfig } from '@sd-jwt/types';
import type { VcTFetcher } from './sd-jwt-vc-vct';

export type StatusListFetcher = (uri: string) => Promise<string>;
export type StatusValidator = (status: number) => Promise<void>;

/**
* Configuration for SD-JWT-VC
*/
export type SDJWTVCConfig = SDJWTConfig & {
// A function that fetches the status list from the uri. If not provided, the library will assume that the response is a compact JWT.
statusListFetcher?: (uri: string) => Promise<string>;
statusListFetcher?: StatusListFetcher;
// validte the status and decide if the status is valid or not. If not provided, the code will continue if it is 0, otherwise it will throw an error.
statusValidator?: (status: number) => Promise<void>;
statusValidator?: StatusValidator;
// a function that fetches the type metadata format from the uri. If not provided, the library will assume that the response is a TypeMetadataFormat. Caching has to be implemented in this function. If the integrity value is passed, it to be validated according to https://www.w3.org/TR/SRI/
vctFetcher?: VcTFetcher;
// if set to true, it will load the metadata format based on the vct value. If not provided, it will default to false.
loadTypeMetadataFormat?: boolean;
};
Loading

0 comments on commit 96e76a9

Please sign in to comment.