From 14fe51721f7b00c7972d1501f397b6fae74b4af0 Mon Sep 17 00:00:00 2001 From: nichonien Date: Fri, 2 Sep 2022 12:41:06 +0530 Subject: [PATCH] fix: validate issuer verification --- e2e/claims.service.e2e.ts | 42 +++++++++++++++++-- src/modules/claims/claims.service.ts | 23 +++++++--- .../did-registry/did-registry.service.ts | 3 +- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/e2e/claims.service.e2e.ts b/e2e/claims.service.e2e.ts index f1da519f..d435a6ff 100644 --- a/e2e/claims.service.e2e.ts +++ b/e2e/claims.service.e2e.ts @@ -495,8 +495,7 @@ describe('Сlaim tests', () => { requestorFields, }); - expirationTimestamp && - expect(exp).toEqual(Math.trunc(expirationTimestamp / 1000)); + expirationTimestamp && expect(exp).toEqual(expirationTimestamp); expect(claimData).not.toContain({ fields: [{ key: 'temperature', value: 36 }], @@ -843,6 +842,43 @@ describe('Сlaim tests', () => { ).toBe(true); }); + test('enrolment should fail if issuer authoritative credential has expired', async () => { + await signerService.connect(rootOwner, ProviderType.PrivateKey); + await domainsService.createRole({ + roleName: roleName2, + namespace, + data: roles[`${roleName2}.${root}`], + returnSteps: false, + }); + const res = await enrolAndIssue(dynamicIssuer, staticIssuer, { + subjectDID: dynamicIssuerDID, + claimType: `${roleName1}.${root}`, + registrationTypes: [ + RegistrationTypes.OnChain, + RegistrationTypes.OffChain, // role type issuer should have offchain claim + ], + issuerFields: [], + expirationTimestamp: Date.now() + 7000, + }); + + await signerService.connect(dynamicIssuer, ProviderType.PrivateKey); + await claimsService.publishPublicClaim({ + claim: { token: res.issuedToken }, + }); + + const delay = (ms) => new Promise((res) => setTimeout(res, ms)); + await delay(8000); + + return expect( + enrolAndIssue(rootOwner, dynamicIssuer, { + subjectDID: rootOwnerDID, + claimType: `${roleName2}.${root}`, + expirationTimestamp: Date.now() + 100000, + registrationTypes: [RegistrationTypes.OffChain], + }) + ).rejects.toEqual(new Error('Issuer credential has expired')); + }); + test('enrollment with credential/claim default time expiration from role definition', async () => { const requester = rootOwner; const issuer = staticIssuer; @@ -994,7 +1030,7 @@ describe('Сlaim tests', () => { await claimsService.hasOnChainRole(rootOwnerDID, claimType, version) ).toBe(true); expect(expiry).toBe(Math.floor(expirationTimestamp / 1000)); - expect(expiry).toBe(exp); + expect(expiry).toBe(Math.floor(exp / 1000)); }); }); diff --git a/src/modules/claims/claims.service.ts b/src/modules/claims/claims.service.ts index 70e5e4a3..d1ac5721 100644 --- a/src/modules/claims/claims.service.ts +++ b/src/modules/claims/claims.service.ts @@ -74,6 +74,8 @@ import { IssuerVerification, RevocationVerification, RoleEIP191JWT, + isEIP191Jwt, + VerificationResult, } from '@energyweb/vc-verification'; import { DidRegistry } from '../did-registry/did-registry.service'; import { ClaimData } from '../did-registry/did.types'; @@ -470,7 +472,12 @@ export class ClaimsService { } if (registrationTypes.includes(RegistrationTypes.OffChain)) { - await this.verifyIssuer(claimData.claimType); + const issuerVerificationRes = await this.verifyIssuer( + claimData.claimType + ); + if (!issuerVerificationRes.verified) { + throw new Error(issuerVerificationRes.error); + } const vp = await this.issueVerifiablePresentation({ subject: sub, namespace: role, @@ -484,6 +491,7 @@ export class ClaimsService { const publicClaim: IPublicClaim = { did: sub, signer: this._signerService.did, + exp: expirationTimestamp, claimData: { ...strippedClaimData, ...(issuerFields && { issuerFields }), @@ -1227,8 +1235,11 @@ export class ClaimsService { * * @param {String} role Registration types of the claim */ - private async verifyIssuer(role: string): Promise { - await this._issuerVerification.verifyIssuer(this._signerService.did, role); + private async verifyIssuer(role: string): Promise { + return await this._issuerVerification.verifyIssuer( + this._signerService.did, + role + ); } /** @@ -1513,7 +1524,7 @@ export class ClaimsService { errors.push(ERROR_MESSAGES.PROOF_NOT_VERIFIED); } // Date.now() and JWT expiration time both identify the time elapsed since January 1, 1970 00:00:00 UTC - const isExpired = payload?.exp && payload?.exp * 1000 < Date.now(); + const isExpired = payload?.exp && payload?.exp < Date.now(); if (isExpired) { errors.push(ERROR_MESSAGES.CREDENTIAL_EXPIRED); } @@ -1563,9 +1574,9 @@ export class ClaimsService { errors: [ERROR_MESSAGES.NO_CLAIM_RESOLVED], }; } - const credentialIsOffChain = resolvedCredential.eip191Jwt; + const credentialIsOffChain = isEIP191Jwt(resolvedCredential); return credentialIsOffChain - ? this.verifyRoleEIP191JWT(resolvedCredential as RoleEIP191JWT) + ? this.verifyRoleEIP191JWT(resolvedCredential) : this.verifyVc( resolvedCredential as VerifiableCredential ); diff --git a/src/modules/did-registry/did-registry.service.ts b/src/modules/did-registry/did-registry.service.ts index e85a2908..64d2b264 100644 --- a/src/modules/did-registry/did-registry.service.ts +++ b/src/modules/did-registry/did-registry.service.ts @@ -282,11 +282,10 @@ export class DidRegistry { async issuePublicClaim({ token, publicClaim, - expirationTimestamp, }: IssuePublicClaimOptions): Promise { const params = publicClaim || token; if (params) { - return this._issuerClaims.issuePublicClaim(params, expirationTimestamp); + return this._issuerClaims.issuePublicClaim(params); } throw new Error(