Skip to content

Commit

Permalink
fix(sd-jwt): resolved most of the feedback
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <blu3beri@proton.me>
  • Loading branch information
berendsliedrecht committed Nov 2, 2023
1 parent 150a252 commit 90fd94d
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 44 deletions.
12 changes: 2 additions & 10 deletions packages/sd-jwt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,15 @@

### Installation

Make sure you have set up the correct version of Aries Framework JavaScript according to the AFJ repository. To find out which version of AFJ you need to have installed you can run the following command. This will list the required peer dependency for `@aries-framework/core`.

```sh
npm info "@aries-framework/sd-jwt" peerDependencies
```

Then add the sd-jwt module to your project.
Add the `sd-jwt` module to your project.

```sh
yarn add @aries-framework/sd-jwt
```

### Quick start

In order for this module to work, we have to inject it into the agent to access agent functionality. See the example for more information.

### Example of usage
After the installation you can follow the [guide to setup your agent](https://aries.js.org/guides/0.4/getting-started/set-up) and add the following to your agent modules.

```ts
import { SdJwtModule } from '@aries-framework/sd-jwt'
Expand Down
4 changes: 2 additions & 2 deletions packages/sd-jwt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@aries-framework/sd-jwt",
"main": "build/index",
"types": "build/index",
"version": "0.4.1",
"version": "0.4.2",
"files": [
"build"
],
Expand All @@ -28,7 +28,7 @@
"@aries-framework/core": "^0.4.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.0",
"jwt-sd": "^0.0.1-alpha.20"
"jwt-sd": "^0.1.0"
},
"devDependencies": {
"@hyperledger/aries-askar-nodejs": "^0.1.0",
Expand Down
7 changes: 2 additions & 5 deletions packages/sd-jwt/src/SdJwtApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ export class SdJwtApi {
return await this.sdJwtService.verify<Header, Payload>(this.agentContext, sdJwtCompact, options)
}

public async getCredentialRecordByIdM<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
>(id: string): Promise<SdJwtRecord<Header, Payload>> {
return await this.sdJwtService.getCredentialRecordById<Header, Payload>(this.agentContext, id)
public async getCredentialRecordById(id: string): Promise<SdJwtRecord> {
return await this.sdJwtService.getCredentialRecordById(this.agentContext, id)
}

public async getAllCredentialRecords(): Promise<Array<SdJwtRecord>> {
Expand Down
4 changes: 2 additions & 2 deletions packages/sd-jwt/src/SdJwtOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { DisclosureFrame } from 'jwt-sd'
export type SdJwtCreateOptions<Payload extends Record<string, unknown> = Record<string, unknown>> = {
holderDidUrl: string
issuerDidUrl: string
issuerOverrideJsonWebAlgorithm?: JwaSignatureAlgorithm
jsonWebAlgorithm?: JwaSignatureAlgorithm
disclosureFrame?: DisclosureFrame<Payload>
hashingAlgorithm?: HashName
}
Expand All @@ -18,7 +18,7 @@ export type SdJwtReceiveOptions = {
* `includedDisclosureIndices` is not the best API, but it is the best alternative until something like `PEX` is supported
*/
export type SdJwtPresentOptions = {
holderOverrideJsonWebAlgorithm?: JwaSignatureAlgorithm
jsonWebAlgorithm?: JwaSignatureAlgorithm
includedDisclosureIndices?: Array<number>

/**
Expand Down
46 changes: 21 additions & 25 deletions packages/sd-jwt/src/SdJwtService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { AgentContext, JwkJson, Query } from '@aries-framework/core'
import type { Signer, SdJwtVcVerificationResult, Verifier, HasherAndAlgorithm } from 'jwt-sd'

import {
parseDid,
DidResolverService,
getJwaFromKey,
getKeyFromVerificationMethod,
getJwkFromJson,
Key,
Expand Down Expand Up @@ -49,8 +49,7 @@ export class SdJwtService {
algorithm: HasherAlgorithm.Sha256,
hasher: (input: string) => {
const serializedInput = TypedArrayEncoder.fromString(input)
const hash = Hasher.hash(serializedInput, 'sha2-256')
return TypedArrayEncoder.toBase64URL(hash)
return Hasher.hash(serializedInput, 'sha2-256')
},
}
}
Expand Down Expand Up @@ -102,15 +101,15 @@ export class SdJwtService {
holderDidUrl,
disclosureFrame,
hashingAlgorithm = 'sha2-256',
issuerOverrideJsonWebAlgorithm,
jsonWebAlgorithm,
}: SdJwtCreateOptions<Payload>
): Promise<{ sdJwtRecord: SdJwtRecord; compact: string }> {
if (hashingAlgorithm !== 'sha2-256') {
throw new SdJwtError(`Unsupported hashing algorithm used: ${hashingAlgorithm}`)
}

const issuerKeyId = issuerDidUrl.split('#')[1]
if (!issuerKeyId) {
const parsedDid = parseDid(issuerDidUrl)
if (!parsedDid.fragment) {
throw new SdJwtError(
`issuer did url '${issuerDidUrl}' does not contain a '#'. Unable to derive key from did document`
)
Expand All @@ -121,7 +120,7 @@ export class SdJwtService {
issuerDidUrl
)
const issuerKey = getKeyFromVerificationMethod(issuerVerificationMethod)
const alg = getJwaFromKey(issuerKey, issuerOverrideJsonWebAlgorithm)
const alg = jsonWebAlgorithm ?? getJwkFromKey(issuerKey).supportedSignatureAlgorithms[0]

const { verificationMethod: holderVerificationMethod } = await this.resolveDidUrl(agentContext, holderDidUrl)
const holderKey = getKeyFromVerificationMethod(holderVerificationMethod)
Expand All @@ -130,7 +129,7 @@ export class SdJwtService {
const header = {
alg: alg.toString(),
typ: 'vc+sd-jwt',
kid: issuerKeyId,
kid: parsedDid.fragment,
}

const sdJwtVc = new SdJwtVc<typeof header, Payload>({}, { disclosureFrame })
Expand Down Expand Up @@ -175,22 +174,22 @@ export class SdJwtService {

public async receive<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
Payload extends Record<string, unknown> = Record<string, unknown>,
>(
agentContext: AgentContext,
sdJwtCompact: string,
{ issuerDidUrl, holderDidUrl }: SdJwtReceiveOptions
): Promise<SdJwtRecord> {
const sdJwt = SdJwtVc.fromCompact<Header, Payload>(sdJwtCompact)
const sdJwtVc = SdJwtVc.fromCompact<Header, Payload>(sdJwtCompact)

if (!sdJwt.signature) {
if (!sdJwtVc.signature) {
throw new SdJwtError('A signature must be included for an sd-jwt')
}

const { verificationMethod: issuerVerificationMethod } = await this.resolveDidUrl(agentContext, issuerDidUrl)
const issuerKey = getKeyFromVerificationMethod(issuerVerificationMethod)

const isSignatureValid = await sdJwt.verifySignature(this.verifier(agentContext, issuerKey))
const { isSignatureValid } = await sdJwtVc.verify(this.verifier(agentContext, issuerKey))

if (!isSignatureValid) {
throw new SdJwtError('sd-jwt has an invalid signature from the issuer')
Expand All @@ -200,14 +199,14 @@ export class SdJwtService {
const holderKey = getKeyFromVerificationMethod(holderVerificiationMethod)
const holderKeyJwk = getJwkFromKey(holderKey).toJson()

sdJwt.assertClaimInPayload('cnf', { jwk: holderKeyJwk })
sdJwtVc.assertClaimInPayload('cnf', { jwk: holderKeyJwk })

const sdJwtRecord = new SdJwtRecord<Header, Payload>({
sdJwt: {
header: sdJwt.header,
payload: sdJwt.payload,
signature: sdJwt.signature,
disclosures: sdJwt.disclosures?.map((d) => d.decoded),
header: sdJwtVc.header,
payload: sdJwtVc.payload,
signature: sdJwtVc.signature,
disclosures: sdJwtVc.disclosures?.map((d) => d.decoded),
holderDidUrl,
},
})
Expand All @@ -220,14 +219,14 @@ export class SdJwtService {
public async present(
agentContext: AgentContext,
sdJwtRecord: SdJwtRecord,
{ includedDisclosureIndices, verifierMetadata, holderOverrideJsonWebAlgorithm }: SdJwtPresentOptions
{ includedDisclosureIndices, verifierMetadata, jsonWebAlgorithm }: SdJwtPresentOptions
): Promise<string> {
const { verificationMethod: holderVerificationMethod } = await this.resolveDidUrl(
agentContext,
sdJwtRecord.sdJwt.holderDidUrl
)
const holderKey = getKeyFromVerificationMethod(holderVerificationMethod)
const alg = getJwaFromKey(holderKey, holderOverrideJsonWebAlgorithm)
const alg = jsonWebAlgorithm ?? getJwkFromKey(holderKey).supportedSignatureAlgorithms[0]

const header = {
alg: alg.toString(),
Expand Down Expand Up @@ -256,7 +255,7 @@ export class SdJwtService {

public async verify<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
Payload extends Record<string, unknown> = Record<string, unknown>,
>(
agentContext: AgentContext,
sdJwtCompact: string,
Expand Down Expand Up @@ -312,11 +311,8 @@ export class SdJwtService {
}
}

public async getCredentialRecordById<
Header extends Record<string, unknown> = Record<string, unknown>,
Payload extends Record<string, unknown> = Record<string, unknown>
>(agentContext: AgentContext, id: string): Promise<SdJwtRecord<Header, Payload>> {
return (await this.sdJwtRepository.getById(agentContext, id)) as SdJwtRecord<Header, Payload>
public async getCredentialRecordById(agentContext: AgentContext, id: string): Promise<SdJwtRecord> {
return (await this.sdJwtRepository.getById(agentContext, id)) as SdJwtRecord
}

public async getAllCredentialRecords(agentContext: AgentContext): Promise<Array<SdJwtRecord>> {
Expand Down

0 comments on commit 90fd94d

Please sign in to comment.