Skip to content

Commit

Permalink
fix: decoded JWT VPs/VCs did not contain everything
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed Apr 29, 2023
1 parent 01593a4 commit fd7ff68
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 126 deletions.
75 changes: 39 additions & 36 deletions packages/ssi-types/src/mapper/credential-mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,39 +180,42 @@ export class CredentialMapper {
makeCredentialsUniform: boolean = true,
opts?: { maxTimeSkewInMS?: number }
): IVerifiablePresentation {
const { iss, aud, jti, vp, ...rest } = decoded

const presentation: IVerifiablePresentation = {
...decoded.vp,
...rest,
...vp,
}
if (makeCredentialsUniform) {
if (!decoded.vp.verifiableCredential) {
if (!vp.verifiableCredential) {
throw Error('Verifiable Presentation should have a verifiable credential at this point')
}
presentation.verifiableCredential = decoded.vp.verifiableCredential.map((vc) => CredentialMapper.toUniformCredential(vc, opts))
presentation.verifiableCredential = vp.verifiableCredential.map((vc) => CredentialMapper.toUniformCredential(vc, opts))
}
if (decoded.iss) {
if (iss) {
const holder = presentation.holder
if (holder) {
if (holder !== decoded.iss) {
throw new Error(`Inconsistent holders between JWT claim (${decoded.iss}) and VC value (${holder})`)
if (holder !== iss) {
throw new Error(`Inconsistent holders between JWT claim (${iss}) and VC value (${holder})`)
}
}
presentation.holder = decoded.iss
presentation.holder = iss
}
if (decoded.aud) {
if (aud) {
const verifier = presentation.verifier
if (verifier) {
if (verifier !== decoded.aud) {
throw new Error(`Inconsistent holders between JWT claim (${decoded.iss}) and VC value (${verifier})`)
if (verifier !== aud) {
throw new Error(`Inconsistent holders between JWT claim (${aud}) and VC value (${verifier})`)
}
}
presentation.verifier = decoded.aud
presentation.verifier = aud
}
if (decoded.jti) {
if (jti) {
const id = presentation.id
if (id && id !== decoded.jti) {
throw new Error(`Inconsistent VP ids between JWT claim (${decoded.jti}) and VP value (${id})`)
if (id && id !== jti) {
throw new Error(`Inconsistent VP ids between JWT claim (${jti}) and VP value (${id})`)
}
presentation.id = decoded.jti
presentation.id = jti
}
return presentation
}
Expand Down Expand Up @@ -287,15 +290,17 @@ export class CredentialMapper {
decoded: JwtDecodedVerifiableCredential,
opts?: { maxTimeSkewInMS?: number }
): IVerifiableCredential {
const { exp, nbf, iss, vc, sub, jti, ...rest } = decoded
const credential: IVerifiableCredential = {
...decoded.vc,
...rest,
...vc,
}

const maxSkewInMS = opts?.maxTimeSkewInMS !== undefined ? opts.maxTimeSkewInMS : 999

if (decoded.exp) {
if (exp) {
const expDate = credential.expirationDate
const jwtExp = parseInt(decoded.exp.toString())
const jwtExp = parseInt(exp.toString())
// fix seconds to millisecond for the date
const expDateAsStr = jwtExp < 9999999999 ? new Date(jwtExp * 1000).toISOString().replace(/\.000Z/, 'Z') : new Date(jwtExp).toISOString()
if (expDate && expDate !== expDateAsStr) {
Expand All @@ -307,9 +312,9 @@ export class CredentialMapper {
credential.expirationDate = expDateAsStr
}

if (decoded.nbf) {
if (nbf) {
const issuanceDate = credential.issuanceDate
const jwtNbf = parseInt(decoded.nbf.toString())
const jwtNbf = parseInt(nbf.toString())
// fix seconds to millisecs for the date
const nbfDateAsStr = jwtNbf < 9999999999 ? new Date(jwtNbf * 1000).toISOString().replace(/\.000Z/, 'Z') : new Date(jwtNbf).toISOString()
if (issuanceDate && issuanceDate !== nbfDateAsStr) {
Expand All @@ -321,41 +326,39 @@ export class CredentialMapper {
credential.issuanceDate = nbfDateAsStr
}

if (decoded.iss) {
if (iss) {
const issuer = credential.issuer
if (issuer) {
if (typeof issuer === 'string') {
if (issuer !== decoded.iss) {
throw new Error(`Inconsistent issuers between JWT claim (${decoded.iss}) and VC value (${issuer})`)
if (issuer !== iss) {
throw new Error(`Inconsistent issuers between JWT claim (${iss}) and VC value (${issuer})`)
}
} else {
if (issuer.id !== decoded.iss) {
throw new Error(`Inconsistent issuers between JWT claim (${decoded.iss}) and VC value (${issuer.id})`)
if (issuer.id !== iss) {
throw new Error(`Inconsistent issuers between JWT claim (${iss}) and VC value (${issuer.id})`)
}
}
} else {
credential.issuer = decoded.iss
credential.issuer = iss
}
}

if (decoded.sub) {
if (sub) {
const subjects = Array.isArray(credential.credentialSubject) ? credential.credentialSubject : [credential.credentialSubject]
for (let i = 0; i < subjects.length; i++) {
const csId = subjects[i].id
if (csId && csId !== decoded.sub) {
throw new Error(`Inconsistent credential subject ids between JWT claim (${decoded.sub}) and VC value (${csId})`)
if (csId && csId !== sub) {
throw new Error(`Inconsistent credential subject ids between JWT claim (${sub}) and VC value (${csId})`)
}
Array.isArray(credential.credentialSubject)
? (credential.credentialSubject[i].id = decoded.sub)
: (credential.credentialSubject.id = decoded.sub)
Array.isArray(credential.credentialSubject) ? (credential.credentialSubject[i].id = sub) : (credential.credentialSubject.id = sub)
}
}
if (decoded.jti) {
if (jti) {
const id = credential.id
if (id && id !== decoded.jti) {
throw new Error(`Inconsistent credential ids between JWT claim (${decoded.jti}) and VC value (${id})`)
if (id && id !== jti) {
throw new Error(`Inconsistent credential ids between JWT claim (${jti}) and VC value (${id})`)
}
credential.id = decoded.jti
credential.id = jti
}

return credential
Expand Down
110 changes: 20 additions & 90 deletions packages/vc-handler-ld-local/plugin.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@
"description": "Use this purpose for the verification method in the DID when doing a check (defaults to CredentialIssuancePurpose)"
}
},
"required": [
"credential"
],
"required": ["credential"],
"description": "Encapsulates the parameters required to create a\n {@link https://www.w3.org/TR/vc-data-model/#credentials | W3C Verifiable Credential }"
},
"CredentialPayload": {
Expand Down Expand Up @@ -70,9 +68,7 @@
"type": "string"
}
},
"required": [
"issuer"
],
"required": ["issuer"],
"description": "Used as input when creating Verifiable Credentials"
},
"IssuerType": {
Expand All @@ -84,9 +80,7 @@
"type": "string"
}
},
"required": [
"id"
]
"required": ["id"]
},
{
"type": "string"
Expand Down Expand Up @@ -117,10 +111,7 @@
"type": "string"
}
},
"required": [
"id",
"type"
],
"required": ["id", "type"],
"description": "Used for the discovery of information about the current status of a verifiable credential, such as whether it is suspended or revoked. The precise contents of the credential status information is determined by the specific `credentialStatus` type definition, and varies depending on factors such as whether it is simple to implement or if it is privacy-enhancing.\n\nSee {@link https://www.w3.org/TR/vc-data-model/#status | Credential Status }"
},
"IAuthenticationProofPurpose": {
Expand Down Expand Up @@ -318,13 +309,7 @@
]
}
},
"required": [
"@context",
"credentialSubject",
"issuanceDate",
"issuer",
"proof"
]
"required": ["@context", "credentialSubject", "issuanceDate", "issuer", "proof"]
},
"CredentialStatusSP": {
"type": "object",
Expand All @@ -342,10 +327,7 @@
"type": "string"
}
},
"required": [
"id",
"type"
]
"required": ["id", "type"]
},
"CredentialProofSP": {
"type": "object",
Expand Down Expand Up @@ -398,12 +380,7 @@
}
}
},
"required": [
"type",
"created",
"proofPurpose",
"verificationMethod"
],
"required": ["type", "created", "proofPurpose", "verificationMethod"],
"additionalProperties": {
"anyOf": [
{
Expand Down Expand Up @@ -482,9 +459,7 @@
]
}
},
"required": [
"presentation"
],
"required": ["presentation"],
"description": "Encapsulates the parameters required to create a\n {@link https://www.w3.org/TR/vc-data-model/#presentations | W3C Verifiable Presentation }"
},
"PresentationPayload": {
Expand Down Expand Up @@ -527,9 +502,7 @@
"type": "string"
}
},
"required": [
"holder"
],
"required": ["holder"],
"description": "Used as input when creating Verifiable Presentations"
},
"W3CVerifiableCredential": {
Expand Down Expand Up @@ -594,13 +567,7 @@
"type": "string"
}
},
"required": [
"@context",
"credentialSubject",
"issuanceDate",
"issuer",
"proof"
],
"required": ["@context", "credentialSubject", "issuanceDate", "issuer", "proof"],
"description": "Represents a signed Verifiable Credential payload (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#credentials | VC data model }"
},
"CompactJWT": {
Expand Down Expand Up @@ -680,13 +647,7 @@
]
}
},
"required": [
"@context",
"holder",
"proof",
"type",
"verifiableCredential"
]
"required": ["@context", "holder", "proof", "type", "verifiableCredential"]
},
"W3CVerifiableCredentialSP": {
"anyOf": [
Expand Down Expand Up @@ -720,11 +681,7 @@
"description": "List of descriptors of how the claims are being mapped to presentation definition"
}
},
"required": [
"id",
"definition_id",
"descriptor_map"
],
"required": ["id", "definition_id", "descriptor_map"],
"description": "It expresses how the inputs are presented as proofs to a Verifier."
},
"Descriptor": {
Expand All @@ -746,11 +703,7 @@
"description": "The Proof or JWT algorith that the proof is in"
}
},
"required": [
"id",
"path",
"format"
],
"required": ["id", "path", "format"],
"description": "descriptor map laying out the structure of the presentation submission."
},
"IVerifyCredentialLDArgs": {
Expand Down Expand Up @@ -794,18 +747,11 @@
"$ref": "#/components/schemas/interface-ib.es5.d.ts-10057-11521-ib.es5.d.ts-0-217681"
}
},
"required": [
"prototype",
"length",
"arguments",
"caller"
],
"required": ["prototype", "length", "arguments", "caller"],
"description": "Check status function, to check credentials that have a credentialStatus property"
}
},
"required": [
"credential"
],
"required": ["credential"],
"description": "Encapsulates the parameters required to verify a\n {@link https://www.w3.org/TR/vc-data-model/#credentials | W3C Verifiable Credential }"
},
"interface-ib.es5.d.ts-10057-11521-ib.es5.d.ts-0-217681": {
Expand All @@ -820,12 +766,7 @@
"$ref": "#/components/schemas/interface-ib.es5.d.ts-10057-11521-ib.es5.d.ts-0-217681"
}
},
"required": [
"prototype",
"length",
"arguments",
"caller"
]
"required": ["prototype", "length", "arguments", "caller"]
},
"IVerifyPresentationLDArgs": {
"type": "object",
Expand Down Expand Up @@ -876,18 +817,11 @@
"$ref": "#/components/schemas/interface-ib.es5.d.ts-10057-11521-ib.es5.d.ts-0-217681"
}
},
"required": [
"prototype",
"length",
"arguments",
"caller"
],
"required": ["prototype", "length", "arguments", "caller"],
"description": "Check status function, to check credentials that have a credentialStatus property"
}
},
"required": [
"presentation"
],
"required": ["presentation"],
"description": "Encapsulates the parameters required to verify a\n {@link https://www.w3.org/TR/vc-data-model/#presentations | W3C Verifiable Presentation }"
},
"VerifiablePresentation": {
Expand Down Expand Up @@ -947,11 +881,7 @@
"type": "string"
}
},
"required": [
"@context",
"holder",
"proof"
],
"required": ["@context", "holder", "proof"],
"description": "Represents a signed Verifiable Presentation (includes proof), using a JSON representation. See {@link https://www.w3.org/TR/vc-data-model/#presentations | VP data model }"
}
},
Expand Down Expand Up @@ -995,4 +925,4 @@
}
}
}
}
}

0 comments on commit fd7ff68

Please sign in to comment.