Skip to content

Commit

Permalink
Merge pull request #10 from transmute-industries/pre-cli-cleanup
Browse files Browse the repository at this point in the history
WIP
  • Loading branch information
OR13 authored Aug 10, 2024
2 parents a4e9c02 + 7e7cabd commit 5433eb7
Show file tree
Hide file tree
Showing 50 changed files with 567 additions and 2,359 deletions.
209 changes: 105 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ npm i @transmute/vc-jwt-sd --save
```

```ts
import sd from '@transmute/vc-jwt-sd'
import sd from "@transmute/vc-jwt-sd";
```

### Issuer Claims
Expand Down Expand Up @@ -70,28 +70,28 @@ credentialSubject:
### Credential Issuance
```ts

const alg = 'ES384';
const alg = "ES384";
const claimset = `... yaml example above ... `;

const issuerRole = await sd.key.generate(alg);
const issuerId = 'https://university.example/issuers/565049'
const issuerKeyId = `${issuerId}#key-42`
const issuerId = "https://university.example/issuers/565049";
const issuerKeyId = `${issuerId}#key-42`;

const holderRole = await sd.key.generate(alg); // or get it some other way.
const holderId = 'did:example:ebfeb1f712ebc6f1c276e12ec21'
const holderKeyId = `${holderId}#${holderRole.publicKeyJwk.kid}`

const vc = await sd.issuer({
iss: issuerId,
kid: issuerKeyId,
typ: `application/vc+ld+json+sd-jwt`,
secretKeyJwk: issuerRole.secretKeyJwk
})
.issue({
holder: holderKeyId,
claimset
})
const holderId = "did:example:ebfeb1f712ebc6f1c276e12ec21";
const holderKeyId = `${holderId}#${holderRole.publicKeyJwk.kid}`;

const vc = await sd
.issuer({
iss: issuerId,
kid: issuerKeyId,
typ: `application/vc-ld+sd-jwt`,
signer: await sd.jws.signer(issuerRole.privateKeyJwk),
})
.issue({
kid: holderKeyId,
claimset,
});
```

### Holder Disclosure
Expand Down Expand Up @@ -135,50 +135,51 @@ credentialSubject:
### Presentation with Holder Binding
```ts
const audience = 'aud-9877'
const nonce = 'nonce-5486168'
const audience = "aud-9877";
const nonce = "nonce-5486168";
const disclosure = `... yaml example above ... `;
const vp = await sd.holder({
secretKeyJwk: holderRole.secretKeyJwk,
iss: holderId,
kid: holderKeyId
})
.issue({
token: vc,
disclosure,
audience,
nonce
})
const vp = await sd
.holder({
iss: holderId,
kid: holderKeyId,
signer: await sd.jws.signer(holderRole.privateKeyJwk),
})
.issue({
token: vc,
disclosure,
audience,
nonce,
});
```


### Verification by Key Resolution

Some protocols allow for discovery of public keys from identifiers.

🍃 This interface is safer,
since it performs verification internally,
🍃 This interface is safer,
since it performs verification internally,
which will fail closed when the incorrect public key is provided.

```ts
const verification = await sd.verifier({
resolver: {
resolve: async (kid: string) => {
if (kid === issuerKeyId){
return issuerRole.publicKeyJwk
}
if (kid === holderKeyId){
return holderRole.publicKeyJwk
}
throw new Error('Unsupported kid: ' + kid)
}
}
})
.verify({
token: vp,
audience,
nonce
})
const verification = await sd
.verifier({
resolver: {
resolve: async (kid: string) => {
if (kid === issuerKeyId) {
return issuerRole.publicKeyJwk;
}
if (kid === holderKeyId) {
return holderRole.publicKeyJwk;
}
throw new Error("Unsupported kid: " + kid);
},
},
})
.verify({
token: vp,
audience,
nonce,
});
```

### Verification by Token
Expand All @@ -191,56 +192,59 @@ When misconfigured, this interface can lead to decoded values being treated as i
```ts
// for testing, not a real dereferencer
const dereference = async (url: string) => {
if (url.startsWith('https://university.example/issuers/565049')){
return {
if (url.startsWith("https://university.example/issuers/565049")) {
return {
id: issuerKeyId,
type: 'JsonWebKey',
type: "JsonWebKey",
controller: issuerId,
publicKeyJwk: issuerRole.publicKeyJwk
}
publicKeyJwk: issuerRole.publicKeyJwk,
};
}
if (url.startsWith('did:example:ebfeb1f712ebc6f1c276e12ec21')){
return {
if (url.startsWith("did:example:ebfeb1f712ebc6f1c276e12ec21")) {
return {
id: holderKeyId,
type: 'JsonWebKey',
type: "JsonWebKey",
controller: holderId,
publicKeyJwk: holderRole.publicKeyJwk
}
publicKeyJwk: holderRole.publicKeyJwk,
};
}
throw new Error('Unsupported didUrl: ' + didUrl)
}
const verification = await sd.verifier({
verifier: {
verify: async (token: string) => {
const jwt = token.split('~')[0]
const decodedHeader = decodeProtectedHeader(jwt)
if (decodedHeader.typ === 'application/vc+ld+json+sd-jwt'){
const decodedPayload = decodeJwt(jwt)
const iss = (decodedHeader.iss || decodedPayload.iss) as string
const kid = decodedHeader.kid as string
const absoluteDidUrl = kid && kid.startsWith(iss)? kid : `${iss}#${kid}`
const { publicKeyJwk } = await dereference(absoluteDidUrl)
const verifier = await sd.JWS.verifier(publicKeyJwk)
return verifier.verify(jwt)
}
if (decodedHeader.typ === 'kb+jwt'){
const decodedPayload = decodeJwt(jwt)
const iss = (decodedHeader.iss || decodedPayload.iss) as string
const kid = decodedHeader.kid as string
const absoluteDidUrl = kid && kid.startsWith(iss)? kid : `${iss}#${kid}`
const { publicKeyJwk } = await dereference(absoluteDidUrl)
const verifier = await sd.JWS.verifier(publicKeyJwk)
return verifier.verify(jwt)
}
throw new Error('Unsupported token typ')
}
}
})
.verify({
token: vp,
audience,
nonce
})
throw new Error("Unsupported didUrl: " + didUrl);
};
const verification = await sd
.verifier({
verifier: {
verify: async (token: string) => {
const jwt = token.split("~")[0];
const decodedHeader = decodeProtectedHeader(jwt);
if (decodedHeader.typ === "application/vc-ld+sd-jwt") {
const decodedPayload = decodeJwt(jwt);
const iss = (decodedHeader.iss || decodedPayload.iss) as string;
const kid = decodedHeader.kid as string;
const absoluteDidUrl =
kid && kid.startsWith(iss) ? kid : `${iss}#${kid}`;
const { publicKeyJwk } = await dereference(absoluteDidUrl);
const verifier = await sd.jws.verifier(publicKeyJwk);
return verifier.verify(jwt);
}
if (decodedHeader.typ === "kb+jwt") {
const decodedPayload = decodeJwt(jwt);
const iss = (decodedHeader.iss || decodedPayload.iss) as string;
const kid = decodedHeader.kid as string;
const absoluteDidUrl =
kid && kid.startsWith(iss) ? kid : `${iss}#${kid}`;
const { publicKeyJwk } = await dereference(absoluteDidUrl);
const verifier = await sd.jws.verifier(publicKeyJwk);
return verifier.verify(jwt);
}
throw new Error("Unsupported token typ");
},
},
})
.verify({
token: vp,
audience,
nonce,
});
```

### Validation
Expand All @@ -253,22 +257,19 @@ This is the result of the verification operations above:
"protectedHeader": {
"alg": "ES384",
"kid": "https://university.example/issuers/565049#key-42",
"typ": "application/vc+ld+json+sd-jwt"
"typ": "application/vc-ld+sd-jwt"
},
"claimset": {
"iss": "https://university.example/issuers/565049",
"cnf": {
"jkt": "did:example:ebfeb1f712ebc6f1c276e12ec21#KmC0EKbs0kL2v6kxPP_c4g-HMMy-n8C5NwtN2tH_msc"
"kid": "did:example:ebfeb1f712ebc6f1c276e12ec21#Sw_eFytRRCLX22cd-ReZxnndRL4ydwNcWWTcuFO5ljw"
},
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "http://university.example/credentials/3732",
"type": [
"VerifiableCredential",
"ExampleDegreeCredential"
],
"type": ["VerifiableCredential", "ExampleDegreeCredential"],
"issuer": {
"id": "https://university.example/issuers/565049",
"name": [
Expand Down Expand Up @@ -306,7 +307,7 @@ This is the result of the verification operations above:
"type": "ExampleBachelorDegree",
"subtype": "Bachelor of Science and Arts"
}
},
}
}
}
```
Expand Down Expand Up @@ -343,4 +344,4 @@ Other implementations
- https://github.com/danielfett/sd-jwt
- https://github.com/christianpaquin/sd-jwt
- https://github.com/chike0905/sd-jwt-ts
- https://github.com/or13/vc-sd-jwt
- https://github.com/or13/vc-sd-jwt
Loading

0 comments on commit 5433eb7

Please sign in to comment.