From cae93f0f122fc163283c9e7865cb87c6350ded21 Mon Sep 17 00:00:00 2001 From: Emanuele De Cupis Date: Thu, 3 Aug 2023 14:55:00 +0200 Subject: [PATCH] add jwt verification --- .../scenarios/cross-device-flow-with-rp.tsx | 11 +++----- src/rp/index.ts | 27 ++++++++++++++++--- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/example/src/scenarios/cross-device-flow-with-rp.tsx b/example/src/scenarios/cross-device-flow-with-rp.tsx index cf3df26f..a4d69cb6 100644 --- a/example/src/scenarios/cross-device-flow-with-rp.tsx +++ b/example/src/scenarios/cross-device-flow-with-rp.tsx @@ -63,21 +63,18 @@ export default async () => { // get signature for dpop const DPoPSignature = await sign(unsignedDPoP, WIA.keytag); + // resolve RP's entity configuration + const entity = await RP.getEntityConfiguration(); + // get request object const requestObj = await SignJWT.appendSignature( unsignedDPoP, DPoPSignature - ).then((t) => RP.getRequestObject(t)); - - // resolve RP's entity configuration - const entity = await RP.getEntityConfiguration(); + ).then((t) => RP.getRequestObject(t, entity)); // Attest Relying Party trust // TODO [SIW-354] - // Validate Request object signature - // TODO [SIW-337] - // select claims to be disclose from pid // these would be selected by users in the UI const claims = [ diff --git a/src/rp/index.ts b/src/rp/index.ts index 7948efe8..003174d4 100644 --- a/src/rp/index.ts +++ b/src/rp/index.ts @@ -9,6 +9,7 @@ import { sha256ToBase64, SignJWT, EncryptJwe, + verify, } from "@pagopa/io-react-native-jwt"; import { QRCodePayload, @@ -97,15 +98,18 @@ export class RelyingPartySolution { /** * Obtain the Request Object for RP authentication + * @see https://italia.github.io/eudi-wallet-it-docs/versione-corrente/en/relying-party-solution.html * - * @function + * @async @function * @param signedWalletInstanceDPoP JWT of the Wallet Instance Attestation DPoP * * @returns The Request Object JWT + * @throws {NoSuitableKeysFoundInEntityConfiguration} When the Request Object is signed with a key not listed in RP's entity configuration * */ async getRequestObject( - signedWalletInstanceDPoP: string + signedWalletInstanceDPoP: string, + entity: RpEntityConfiguration ): Promise { const decodedJwtDPop = await decodeJwt(signedWalletInstanceDPoP); const requestUri = decodedJwtDPop.payload.htu as string; @@ -119,11 +123,28 @@ export class RelyingPartySolution { if (response.status === 200) { const responseText = await response.text(); - const responseJwt = await decodeJwt(responseText); + const responseJwt = decodeJwt(responseText); + + // verify token signature according to RP's entity configuration + // to ensure the request object is authentic + { + const pubKey = entity.payload.jwks.keys.find( + ({ kid }) => kid === responseJwt.protectedHeader.kid + ); + if (!pubKey) { + throw new NoSuitableKeysFoundInEntityConfiguration( + "Request Object signature verification" + ); + } + await verify(responseText, pubKey); + } + + // parse request object it has the expected shape by specification const requestObj = RequestObject.parse({ header: responseJwt.protectedHeader, payload: responseJwt.payload, }); + return requestObj; }