Coder Social home page Coder Social logo

transmute-industries / vc-jwt-sd Goto Github PK

View Code? Open in Web Editor NEW
5.0 3.0 3.0 1.2 MB

Experimental implementation of sd-jwt for W3C Verifiable Credentials

Home Page: https://github.com/transmute-industries/vc-jwt-sd

License: Apache License 2.0

JavaScript 0.44% TypeScript 99.56%
jose jsonld jwt sd-jwt selective-disclosure yaml

vc-jwt-sd's Introduction

@transmute/vc-jwt-sd

CI Branches Functions Lines Statements Jest coverage

๐Ÿšง Experimental implementation of sd-jwt for use with W3C Verifiable Credentials. ๐Ÿ”ฅ

Usage

npm i @transmute/vc-jwt-sd --save
import sd from '@transmute/vc-jwt-sd'

Issuer Claims

This implementation relies on custom yaml tags to indicate disclosability:

# Based on https://w3c.github.io/vc-data-model/#example-a-simple-example-of-a-verifiable-credential
"@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
issuer:
  id: https://university.example/issuers/565049
  name:
    - value: test value 0
      lang: en
    - !sd # indicates a disclosable claim
      value: test value 1
      lang: en
    - value: test value 2
      lang: en
    - !sd # indicates a disclosable claim
      value: test value 3
      lang: en
    - value: test value 4
      lang: en
validFrom: 2015-05-10T12:30:00Z
credentialStatus:
  - id: https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6#0
    type: StatusList2021Entry
    statusPurpose: revocation
    statusListIndex: "0"
    statusListCredential: https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6
credentialSubject:
  id: did:example:ebfeb1f712ebc6f1c276e12ec21
  degree:
    type: ExampleBachelorDegree
    subtype: Bachelor of Science and Arts

Credential Issuance

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 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
})

Holder Disclosure

This implementation relies on yaml to indicate holder disclosures:

"@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
issuer:
  id: https://university.example/issuers/565049
  name:
    - value: test value 0
      lang: en
    - value: test value 1 # The value or True can be provided to signal intentional disclosure.
      lang: en
    - value: test value 2
      lang: en
    - False # This boolean indicates that this claim should not be disclosed in a presentation
    - value: test value 4
      lang: en
validFrom: 2015-05-10T12:30:00Z
credentialStatus:
  - id: https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6#0
    type: StatusList2021Entry
    statusPurpose: revocation
    statusListIndex: "0"
    statusListCredential: https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6
credentialSubject:
  id: did:example:ebfeb1f712ebc6f1c276e12ec21
  degree:
    type: ExampleBachelorDegree
    subtype: Bachelor of Science and Arts

Presentation with Holder Binding

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
})

Verification by Key Resolution

Some protocols allow for discovery of public keys from identifiers.

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

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

Some protocols require disovery of public keys from protected header and payload claims.

๐Ÿ‚ This interface is less safe, but more flexible. When misconfigured, this interface can lead to decoded values being treated as if they had been verified.

// for testing, not a real dereferencer
const dereference = async (url: string) => {
  if (url.startsWith('https://university.example/issuers/565049')){
    return { 
      id: issuerKeyId,
      type: 'JsonWebKey',
      controller: issuerId,
      publicKeyJwk: issuerRole.publicKeyJwk
    }
  }
  if (url.startsWith('did:example:ebfeb1f712ebc6f1c276e12ec21')){
    return { 
      id: holderKeyId,
      type: 'JsonWebKey',
      controller: holderId,
      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
})

Validation

๐Ÿšง This library does not perform validation currently. 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"
  },
  "claimset": {
    "iss": "https://university.example/issuers/565049",
    "cnf": {
      "jkt": "did:example:ebfeb1f712ebc6f1c276e12ec21#KmC0EKbs0kL2v6kxPP_c4g-HMMy-n8C5NwtN2tH_msc"
    },
    "@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"
    ],
    "issuer": {
      "id": "https://university.example/issuers/565049",
      "name": [
        {
          "value": "test value 0",
          "lang": "en"
        },
        {
          "value": "test value 1",
          "lang": "en"
        },
        {
          "value": "test value 2",
          "lang": "en"
        },
        {
          "value": "test value 4",
          "lang": "en"
        }
      ]
    },
    "validFrom": "2015-05-10T12:30:00Z",
    "credentialStatus": [
      {
        "id": "https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6#0",
        "type": "StatusList2021Entry",
        "statusPurpose": "revocation",
        "statusListIndex": "0",
        "statusListCredential": "https://vendor.example/status-list/urn:uuid:d31ada5d-1d3d-4f68-8587-8ff9bb3038d6"
      }
    ],
    "credentialSubject": {
      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
      "degree": {
        "type": "ExampleBachelorDegree",
        "subtype": "Bachelor of Science and Arts"
      }
    },
  }
}

Develop

npm i
npm t
npm run lint
npm run build

Integration Tests

Synching tests cases from reference implementation

git clone [email protected]:danielfett/sd-jwt.git
cd sd-jwt
python3 -m venv venv
source venv/bin/activate
pip install git+https://github.com/danielfett/sd-jwt.git
cd tests/testcases
sd-jwt-generate example
cd ..
cp -r ./testcases ../../testcases

Other implementations

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.