{"version":3,"file":"W3cJwtCredentialService.mjs","names":[],"sources":["../../../../src/modules/vc/jwt-vc/W3cJwtCredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent/context'\nimport type { VerifyJwsResult } from '../../../crypto/JwsService'\nimport { JwsService } from '../../../crypto/JwsService'\nimport { CredoError } from '../../../error'\nimport { injectable } from '../../../plugins'\nimport { asArray, isDid, MessageValidator } from '../../../utils'\nimport type { DidPurpose, VerificationMethod } from '../../dids'\nimport { DidResolverService, DidsApi, parseDid } from '../../dids'\nimport {\n  getPublicJwkFromVerificationMethod,\n  getSupportedVerificationMethodTypesForPublicJwk,\n} from '../../dids/domain/key-type/keyDidMapping'\nimport { type KnownJwaSignatureAlgorithm, PublicJwk } from '../../kms'\nimport { W3cJsonLdVerifiableCredential } from '../data-integrity'\nimport type { SingleValidationResult, W3cVerifyCredentialResult, W3cVerifyPresentationResult } from '../models'\nimport type {\n  W3cJwtSignCredentialOptions,\n  W3cJwtSignPresentationOptions,\n  W3cJwtVerifyCredentialOptions,\n  W3cJwtVerifyPresentationOptions,\n} from '../W3cCredentialServiceOptions'\nimport { getJwtPayloadFromCredential } from './credentialTransformer'\nimport { getJwtPayloadFromPresentation } from './presentationTransformer'\nimport { W3cJwtVerifiableCredential } from './W3cJwtVerifiableCredential'\nimport { W3cJwtVerifiablePresentation } from './W3cJwtVerifiablePresentation'\n\n/**\n * Supports signing and verification of credentials according to the [Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model)\n * using [Json Web Tokens](https://www.w3.org/TR/vc-data-model/#json-web-token).\n */\n@injectable()\nexport class W3cJwtCredentialService {\n  private jwsService: JwsService\n\n  public constructor(jwsService: JwsService) {\n    this.jwsService = jwsService\n  }\n\n  /**\n   * Signs a credential\n   */\n  public async signCredential(\n    agentContext: AgentContext,\n    options: W3cJwtSignCredentialOptions\n  ): Promise<W3cJwtVerifiableCredential> {\n    // Validate the instance\n    MessageValidator.validateSync(options.credential)\n\n    // Get the JWT payload for the JWT based on the JWT Encoding rules form the VC-DATA-MODEL\n    // https://www.w3.org/TR/vc-data-model/#jwt-encoding\n    const jwtPayload = getJwtPayloadFromCredential(options.credential)\n\n    if (!isDid(options.verificationMethod)) {\n      throw new CredoError('Only did identifiers are supported as verification method')\n    }\n\n    const publicJwk = await this.resolveVerificationMethod(agentContext, options.verificationMethod, [\n      'assertionMethod',\n    ])\n\n    const jwt = await this.jwsService.createJwsCompact(agentContext, {\n      payload: jwtPayload,\n      keyId: publicJwk.keyId,\n      protectedHeaderOptions: {\n        typ: 'JWT',\n        alg: options.alg,\n        kid: options.verificationMethod,\n      },\n    })\n\n    // TODO: this re-parses and validates the credential in the JWT, which is not necessary.\n    // We should somehow create an instance of W3cJwtVerifiableCredential directly from the JWT\n    const jwtVc = W3cJwtVerifiableCredential.fromSerializedJwt(jwt)\n\n    return jwtVc\n  }\n\n  /**\n   * Verifies the signature(s) of a credential\n   *\n   * @param credential the credential to be verified\n   * @returns the verification result\n   */\n  public async verifyCredential(\n    agentContext: AgentContext,\n    options: W3cJwtVerifyCredentialOptions\n  ): Promise<W3cVerifyCredentialResult> {\n    // NOTE: this is mostly from the JSON-LD service that adds this option. Once we support\n    // the same granular validation results, we can remove this and the user could just check\n    // which of the validations failed. Supporting for consistency with the JSON-LD service for now.\n    const verifyCredentialStatus = options.verifyCredentialStatus ?? true\n\n    const validationResults: W3cVerifyCredentialResult = {\n      isValid: false,\n      validations: {},\n    }\n\n    try {\n      let credential: W3cJwtVerifiableCredential\n      try {\n        // If instance is provided as input, we want to validate the credential (otherwise it's done in the fromSerializedJwt method below)\n        if (options.credential instanceof W3cJwtVerifiableCredential) {\n          MessageValidator.validateSync(options.credential.credential)\n        }\n\n        credential =\n          options.credential instanceof W3cJwtVerifiableCredential\n            ? options.credential\n            : W3cJwtVerifiableCredential.fromSerializedJwt(options.credential)\n\n        // Verify the JWT payload (verifies whether it's not expired, etc...)\n        credential.jwt.payload.validate({\n          skewSeconds: agentContext.config.validitySkewSeconds,\n        })\n\n        validationResults.validations.dataModel = {\n          isValid: true,\n        }\n      } catch (error) {\n        validationResults.validations.dataModel = {\n          isValid: false,\n          error,\n        }\n\n        return validationResults\n      }\n\n      const issuerVerificationMethod = await this.getVerificationMethodForJwtCredential(agentContext, {\n        credential,\n        purpose: ['assertionMethod'],\n      })\n      const issuerPublicKey = getPublicJwkFromVerificationMethod(issuerVerificationMethod)\n\n      let signatureResult: VerifyJwsResult | undefined\n      try {\n        // Verify the JWS signature\n        signatureResult = await this.jwsService.verifyJws(agentContext, {\n          jws: credential.jwt.serializedJwt,\n          // We have pre-fetched the key based on the issuer/signer of the credential\n          jwsSigner: {\n            method: 'did',\n            jwk: issuerPublicKey,\n            didUrl: issuerVerificationMethod.id,\n          },\n        })\n\n        if (!signatureResult.isValid) {\n          validationResults.validations.signature = {\n            isValid: false,\n            error: new CredoError('Invalid JWS signature'),\n          }\n        } else {\n          validationResults.validations.signature = {\n            isValid: true,\n          }\n        }\n      } catch (error) {\n        validationResults.validations.signature = {\n          isValid: false,\n          error,\n        }\n      }\n\n      // Validate whether the credential is signed with the 'issuer' id\n      // NOTE: this uses the verificationMethod.controller. We may want to use the verificationMethod.id?\n      if (credential.issuerId !== issuerVerificationMethod.controller) {\n        validationResults.validations.issuerIsSigner = {\n          isValid: false,\n          error: new CredoError(\n            `Credential is signed using verification method ${issuerVerificationMethod.id}, while the issuer of the credential is '${credential.issuerId}'`\n          ),\n        }\n      } else {\n        validationResults.validations.issuerIsSigner = {\n          isValid: true,\n        }\n      }\n\n      // Validate whether the `issuer` of the credential is also the signer\n      const issuerIsSigner = signatureResult?.jwsSigners.some(\n        (jwsSigner) => jwsSigner.jwk.fingerprint === issuerPublicKey.fingerprint\n      )\n      if (!issuerIsSigner) {\n        validationResults.validations.issuerIsSigner = {\n          isValid: false,\n          error: new CredoError('Credential is not signed by the issuer of the credential'),\n        }\n      } else {\n        validationResults.validations.issuerIsSigner = {\n          isValid: true,\n        }\n      }\n\n      // Validate credentialStatus\n      if (verifyCredentialStatus && !credential.credentialStatus) {\n        validationResults.validations.credentialStatus = {\n          isValid: true,\n        }\n      } else if (verifyCredentialStatus && credential.credentialStatus) {\n        validationResults.validations.credentialStatus = {\n          isValid: false,\n          error: new CredoError('Verifying credential status is not supported for JWT VCs'),\n        }\n      }\n\n      validationResults.isValid = Object.values(validationResults.validations).every((v) => v.isValid)\n\n      return validationResults\n    } catch (error) {\n      validationResults.error = error\n      return validationResults\n    }\n  }\n\n  /**\n   * Signs a presentation including the credentials it includes\n   *\n   * @param presentation the presentation to be signed\n   * @returns the signed presentation\n   */\n  public async signPresentation(\n    agentContext: AgentContext,\n    options: W3cJwtSignPresentationOptions\n  ): Promise<W3cJwtVerifiablePresentation> {\n    // Validate the instance\n    MessageValidator.validateSync(options.presentation)\n\n    // Get the JWT payload for the JWT based on the JWT Encoding rules form the VC-DATA-MODEL\n    // https://www.w3.org/TR/vc-data-model/#jwt-encoding\n    const jwtPayload = getJwtPayloadFromPresentation(options.presentation)\n\n    // Set the nonce so it's included in the signature\n    jwtPayload.additionalClaims.nonce = options.challenge\n    jwtPayload.aud = options.domain\n\n    const publicJwk = await this.resolveVerificationMethod(agentContext, options.verificationMethod, ['authentication'])\n\n    const jwt = await this.jwsService.createJwsCompact(agentContext, {\n      payload: jwtPayload,\n      keyId: publicJwk.keyId,\n      protectedHeaderOptions: {\n        typ: 'JWT',\n        alg: options.alg,\n        kid: options.verificationMethod,\n      },\n    })\n\n    // TODO: this re-parses and validates the presentation in the JWT, which is not necessary.\n    // We should somehow create an instance of W3cJwtVerifiablePresentation directly from the JWT\n    const jwtVp = W3cJwtVerifiablePresentation.fromSerializedJwt(jwt)\n\n    return jwtVp\n  }\n\n  /**\n   * Verifies a presentation including the credentials it includes\n   *\n   * @param presentation the presentation to be verified\n   * @returns the verification result\n   */\n  public async verifyPresentation(\n    agentContext: AgentContext,\n    options: W3cJwtVerifyPresentationOptions\n  ): Promise<W3cVerifyPresentationResult> {\n    const validationResults: W3cVerifyPresentationResult = {\n      isValid: false,\n      validations: {},\n    }\n\n    try {\n      let presentation: W3cJwtVerifiablePresentation\n      try {\n        // If instance is provided as input, we want to validate the presentation\n        if (options.presentation instanceof W3cJwtVerifiablePresentation) {\n          MessageValidator.validateSync(options.presentation.presentation)\n        }\n\n        presentation =\n          options.presentation instanceof W3cJwtVerifiablePresentation\n            ? options.presentation\n            : W3cJwtVerifiablePresentation.fromSerializedJwt(options.presentation)\n\n        // Verify the JWT payload (verifies whether it's not expired, etc...)\n        presentation.jwt.payload.validate({\n          skewSeconds: agentContext.config.validitySkewSeconds,\n        })\n\n        // Make sure challenge matches nonce\n        if (options.challenge !== presentation.jwt.payload.additionalClaims.nonce) {\n          throw new CredoError(`JWT payload 'nonce' does not match challenge '${options.challenge}'`)\n        }\n\n        const audArray = asArray(presentation.jwt.payload.aud)\n        if (options.domain && !audArray.includes(options.domain)) {\n          throw new CredoError(`JWT payload 'aud' does not include domain '${options.domain}'`)\n        }\n\n        validationResults.validations.dataModel = {\n          isValid: true,\n        }\n      } catch (error) {\n        validationResults.validations.dataModel = {\n          isValid: false,\n          error,\n        }\n\n        return validationResults\n      }\n\n      const proverVerificationMethod = await this.getVerificationMethodForJwtCredential(agentContext, {\n        credential: presentation,\n        purpose: ['authentication'],\n      })\n      const proverPublicKey = getPublicJwkFromVerificationMethod(proverVerificationMethod)\n\n      let signatureResult: VerifyJwsResult | undefined\n      try {\n        // Verify the JWS signature\n        signatureResult = await this.jwsService.verifyJws(agentContext, {\n          jws: presentation.jwt.serializedJwt,\n          allowedJwsSignerMethods: ['did'],\n          jwsSigner: {\n            method: 'did',\n            didUrl: proverVerificationMethod.id,\n            jwk: proverPublicKey,\n          },\n          trustedCertificates: [],\n        })\n\n        if (!signatureResult.isValid) {\n          validationResults.validations.presentationSignature = {\n            isValid: false,\n            error: new CredoError('Invalid JWS signature on presentation'),\n          }\n        } else {\n          validationResults.validations.presentationSignature = {\n            isValid: true,\n          }\n        }\n      } catch (error) {\n        validationResults.validations.presentationSignature = {\n          isValid: false,\n          error,\n        }\n      }\n\n      // Validate whether the presentation is signed with the 'holder' id\n      // NOTE: this uses the verificationMethod.controller. We may want to use the verificationMethod.id?\n      if (presentation.holderId && proverVerificationMethod.controller !== presentation.holderId) {\n        validationResults.validations.holderIsSigner = {\n          isValid: false,\n          error: new CredoError(\n            `Presentation is signed using verification method ${proverVerificationMethod.id}, while the holder of the presentation is '${presentation.holderId}'`\n          ),\n        }\n      } else {\n        // If no holderId is present, this validation passes by default as there can't be\n        // a mismatch between the 'holder' property and the signer of the presentation.\n        validationResults.validations.holderIsSigner = {\n          isValid: true,\n        }\n      }\n\n      // To keep things simple, we only support JWT VCs in JWT VPs for now\n      const credentials = asArray(presentation.presentation.verifiableCredential)\n\n      // Verify all credentials in parallel, and await the result\n      validationResults.validations.credentials = await Promise.all(\n        credentials.map(async (credential) => {\n          if (credential instanceof W3cJsonLdVerifiableCredential) {\n            return {\n              isValid: false,\n              error: new CredoError(\n                'Credential is of format ldp_vc. presentations in jwt_vp format can only contain credentials in jwt_vc format'\n              ),\n              validations: {},\n            }\n          }\n\n          const credentialResult = await this.verifyCredential(agentContext, {\n            credential,\n            verifyCredentialStatus: options.verifyCredentialStatus,\n          })\n\n          let credentialSubjectAuthentication: SingleValidationResult\n\n          // Check whether any of the credentialSubjectIds for each credential is the same as the controller of the verificationMethod\n          // This authenticates the presentation creator controls one of the credentialSubject ids.\n          // NOTE: this doesn't take into account the case where the credentialSubject is no the holder. In the\n          // future we can add support for other flows, but for now this is the most common use case.\n          // TODO: should this be handled on a higher level? I don't really see it being handled in the jsonld lib\n          // or in the did-jwt-vc lib (it seems they don't even verify the credentials itself), but we probably need some\n          // more experience on the use cases before we loosen the restrictions (as it means we need to handle it on a higher layer).\n          const credentialSubjectIds = credential.credentialSubjectIds\n          const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some(\n            (subjectId) => proverVerificationMethod.controller === subjectId\n          )\n\n          if (credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject) {\n            credentialSubjectAuthentication = {\n              isValid: false,\n              error: new CredoError(\n                'Credential has one or more credentialSubject ids, but presentation does not authenticate credential subject'\n              ),\n            }\n          } else {\n            credentialSubjectAuthentication = {\n              isValid: true,\n            }\n          }\n\n          return {\n            ...credentialResult,\n            isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid,\n            validations: {\n              ...credentialResult.validations,\n              credentialSubjectAuthentication,\n            },\n          }\n        })\n      )\n\n      // Deeply nested check whether all validations have passed\n      validationResults.isValid = Object.values(validationResults.validations).every((v) =>\n        Array.isArray(v) ? v.every((vv) => vv.isValid) : v.isValid\n      )\n\n      return validationResults\n    } catch (error) {\n      validationResults.error = error\n      return validationResults\n    }\n  }\n\n  private async resolveVerificationMethod(\n    agentContext: AgentContext,\n    verificationMethod: string,\n    allowsPurposes?: DidPurpose[]\n  ): Promise<PublicJwk> {\n    const dids = agentContext.resolve(DidsApi)\n\n    const parsedDid = parseDid(verificationMethod)\n    const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(parsedDid.did)\n    const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes)\n    const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodObject)\n\n    publicJwk.keyId =\n      keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))\n        ?.kmsKeyId ?? publicJwk.legacyKeyId\n\n    return publicJwk\n  }\n\n  /**\n   * This method tries to find the verification method associated with the JWT credential or presentation.\n   * This verification method can then be used to verify the credential or presentation signature.\n   *\n   * The following methods are used to extract the verification method:\n   *  - verification method is resolved based on the `kid` in the protected header\n   *    - either as absolute reference (e.g. `did:example:123#key-1`)\n   *    - or as relative reference to the `iss` of the JWT (e.g. `iss` is `did:example:123` and `kid` is `#key-1`)\n   *  - the did document is resolved based on the `iss` field, after which the verification method is extracted based on the `alg`\n   *    used to sign the JWT and the specified `purpose`. Only a single verification method may be present, and in all other cases,\n   *    an error is thrown.\n   *\n   * The signer (`iss`) of the JWT is verified against the `controller` of the verificationMethod resolved in the did\n   * document. This means if the `iss` of a credential is `did:example:123` and the controller of the verificationMethod\n   * is `did:example:456`, an error is thrown to prevent the JWT from successfully being verified.\n   *\n   * In addition the JWT must conform to one of the following rules:\n   *   - MUST be a credential and have an `iss` field and MAY have an absolute or relative `kid`\n   *   - MUST not be a credential AND ONE of the following:\n   *      - have an `iss` field and MAY have an absolute or relative `kid`\n   *      - does not have an `iss` field and MUST have an absolute `kid`\n   */\n  private async getVerificationMethodForJwtCredential(\n    agentContext: AgentContext,\n    options: {\n      credential: W3cJwtVerifiableCredential | W3cJwtVerifiablePresentation\n      purpose?: DidPurpose[]\n    }\n  ) {\n    const { credential, purpose } = options\n    const kid = credential.jwt.header.kid\n\n    const didResolver = agentContext.dependencyManager.resolve(DidResolverService)\n\n    // The signerId is the `holder` of the presentation or the `issuer` of the credential\n    // For a credential only the `iss` COULD be enough to resolve the signer key (see method comments)\n    const signerId = credential.jwt.payload.iss\n\n    let verificationMethod: VerificationMethod\n\n    // If the kid starts with # we assume it is a relative did url, and we resolve it based on the `iss` and the `kid`\n    if (kid?.startsWith('#')) {\n      if (!signerId) {\n        throw new CredoError(`JWT 'kid' MUST be absolute when when no 'iss' is present in JWT payload`)\n      }\n\n      const didDocument = await didResolver.resolveDidDocument(agentContext, signerId)\n      verificationMethod = didDocument.dereferenceKey(`${signerId}${kid}`, purpose)\n    }\n    // this is a full did url (todo check if it contains a #)\n    else if (kid && isDid(kid)) {\n      const didDocument = await didResolver.resolveDidDocument(agentContext, kid)\n\n      verificationMethod = didDocument.dereferenceKey(kid, purpose)\n\n      if (signerId && didDocument.id !== signerId) {\n        throw new CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${signerId}'`)\n      }\n    } else {\n      if (!signerId) {\n        throw new CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`)\n      }\n\n      // Find the verificationMethod in the did document based on the alg and proofPurpose\n      const jwkClass = PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(\n        credential.jwt.header.alg as KnownJwaSignatureAlgorithm\n      )\n      const supportedVerificationMethodTypes = getSupportedVerificationMethodTypesForPublicJwk(jwkClass)\n\n      const didDocument = await didResolver.resolveDidDocument(agentContext, signerId)\n      const verificationMethods =\n        didDocument.assertionMethod\n          ?.map((v) => (typeof v === 'string' ? didDocument.dereferenceVerificationMethod(v) : v))\n          .filter((v) => supportedVerificationMethodTypes.includes(v.type)) ?? []\n\n      if (verificationMethods.length === 0) {\n        throw new CredoError(\n          `No verification methods found for signer '${signerId}' and key type '${jwkClass.name}' for alg '${credential.jwt.header.alg}'. Unable to determine which public key is associated with the credential.`\n        )\n      }\n      if (verificationMethods.length > 1) {\n        throw new CredoError(\n          `Multiple verification methods found for signer '${signerId}' and key type '${jwkClass.name}' for alg '${credential.jwt.header.alg}'. Unable to determine which public key is associated with the credential.`\n        )\n      }\n\n      verificationMethod = verificationMethods[0]\n    }\n\n    // Verify the controller of the verificationMethod matches the signer of the credential\n    if (signerId && verificationMethod.controller !== signerId) {\n      throw new CredoError(\n        `Verification method controller '${verificationMethod.controller}' does not match the signer '${signerId}'`\n      )\n    }\n\n    return verificationMethod\n  }\n}\n"],"mappings":"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"}