@pagopa/io-react-native-wallet 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/lib/commonjs/credential/issuance/03-start-user-authorization.js +3 -0
  2. package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
  3. package/lib/commonjs/credential/presentation/01-start-flow.js +12 -28
  4. package/lib/commonjs/credential/presentation/01-start-flow.js.map +1 -1
  5. package/lib/commonjs/credential/presentation/04-retrieve-rp-jwks.js +96 -24
  6. package/lib/commonjs/credential/presentation/04-retrieve-rp-jwks.js.map +1 -1
  7. package/lib/commonjs/credential/presentation/05-verify-request-object.js +7 -2
  8. package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
  9. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +9 -5
  10. package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  11. package/lib/commonjs/credential/presentation/08-send-authorization-response.js +20 -16
  12. package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
  13. package/lib/commonjs/credential/presentation/README.md +4 -4
  14. package/lib/commonjs/credential/presentation/errors.js +2 -19
  15. package/lib/commonjs/credential/presentation/errors.js.map +1 -1
  16. package/lib/commonjs/credential/presentation/types.js +9 -1
  17. package/lib/commonjs/credential/presentation/types.js.map +1 -1
  18. package/lib/commonjs/entity/trust/chain.js.map +1 -1
  19. package/lib/commonjs/utils/crypto.js +41 -1
  20. package/lib/commonjs/utils/crypto.js.map +1 -1
  21. package/lib/commonjs/utils/decoder.js.map +1 -1
  22. package/lib/module/credential/issuance/03-start-user-authorization.js +3 -0
  23. package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
  24. package/lib/module/credential/presentation/01-start-flow.js +12 -28
  25. package/lib/module/credential/presentation/01-start-flow.js.map +1 -1
  26. package/lib/module/credential/presentation/04-retrieve-rp-jwks.js +96 -24
  27. package/lib/module/credential/presentation/04-retrieve-rp-jwks.js.map +1 -1
  28. package/lib/module/credential/presentation/05-verify-request-object.js +7 -2
  29. package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
  30. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +9 -5
  31. package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
  32. package/lib/module/credential/presentation/08-send-authorization-response.js +18 -14
  33. package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
  34. package/lib/module/credential/presentation/README.md +4 -4
  35. package/lib/module/credential/presentation/errors.js +0 -16
  36. package/lib/module/credential/presentation/errors.js.map +1 -1
  37. package/lib/module/credential/presentation/types.js +9 -1
  38. package/lib/module/credential/presentation/types.js.map +1 -1
  39. package/lib/module/entity/trust/chain.js.map +1 -1
  40. package/lib/module/utils/crypto.js +38 -0
  41. package/lib/module/utils/crypto.js.map +1 -1
  42. package/lib/module/utils/decoder.js +0 -1
  43. package/lib/module/utils/decoder.js.map +1 -1
  44. package/lib/module/utils/jwk.js.map +1 -1
  45. package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
  46. package/lib/typescript/credential/presentation/01-start-flow.d.ts +3 -3
  47. package/lib/typescript/credential/presentation/01-start-flow.d.ts.map +1 -1
  48. package/lib/typescript/credential/presentation/03-get-request-object.d.ts +1 -1
  49. package/lib/typescript/credential/presentation/04-retrieve-rp-jwks.d.ts +15 -8
  50. package/lib/typescript/credential/presentation/04-retrieve-rp-jwks.d.ts.map +1 -1
  51. package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -1
  52. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +3 -2
  53. package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
  54. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +5 -5
  55. package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
  56. package/lib/typescript/credential/presentation/errors.d.ts +0 -11
  57. package/lib/typescript/credential/presentation/errors.d.ts.map +1 -1
  58. package/lib/typescript/credential/presentation/types.d.ts +252 -3
  59. package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
  60. package/lib/typescript/entity/trust/chain.d.ts +1 -1
  61. package/lib/typescript/entity/trust/chain.d.ts.map +1 -1
  62. package/lib/typescript/utils/crypto.d.ts +24 -0
  63. package/lib/typescript/utils/crypto.d.ts.map +1 -1
  64. package/lib/typescript/utils/decoder.d.ts +1 -1
  65. package/lib/typescript/utils/decoder.d.ts.map +1 -1
  66. package/lib/typescript/utils/jwk.d.ts +2 -0
  67. package/lib/typescript/utils/jwk.d.ts.map +1 -1
  68. package/package.json +4 -2
  69. package/src/credential/issuance/03-start-user-authorization.ts +3 -0
  70. package/src/credential/presentation/01-start-flow.ts +16 -32
  71. package/src/credential/presentation/03-get-request-object.ts +1 -1
  72. package/src/credential/presentation/04-retrieve-rp-jwks.ts +122 -34
  73. package/src/credential/presentation/05-verify-request-object.ts +4 -3
  74. package/src/credential/presentation/07-evaluate-input-descriptor.ts +20 -6
  75. package/src/credential/presentation/08-send-authorization-response.ts +25 -17
  76. package/src/credential/presentation/README.md +4 -4
  77. package/src/credential/presentation/errors.ts +0 -16
  78. package/src/credential/presentation/types.ts +10 -1
  79. package/src/entity/trust/chain.ts +1 -2
  80. package/src/utils/crypto.ts +43 -0
  81. package/src/utils/decoder.ts +1 -1
  82. package/src/utils/jwk.ts +3 -1
@@ -3,6 +3,12 @@ import { hasStatusOrThrow } from "../../utils/misc";
3
3
  import { RelyingPartyEntityConfiguration } from "../../entity/trust/types";
4
4
  import { decode as decodeJwt } from "@pagopa/io-react-native-jwt";
5
5
  import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
6
+ import { RequestObject } from "./types";
7
+ import {
8
+ convertCertToPem,
9
+ parsePublicKey,
10
+ getSigningJwk,
11
+ } from "../../utils/crypto";
6
12
 
7
13
  /**
8
14
  * Defines the signature for a function that retrieves JSON Web Key Sets (JWKS) from a client.
@@ -16,54 +22,136 @@ export type FetchJwks<T extends Array<unknown> = []> = (...args: T) => Promise<{
16
22
  }>;
17
23
 
18
24
  /**
19
- * Retrieves the JSON Web Key Set (JWKS) from the specified client's well-known endpoint.
20
- * It is formed using `{issUrl.base}/.well-known/jar-issuer${issUrl.pah}` as explained in SD-JWT VC issuer metadata section
25
+ * Fetches and parses JWKS from a given URI.
21
26
  *
22
- * @param requestObjectEncodedJwt - Request Object in JWT format.
23
- * @param options - Optional context containing a custom fetch implementation.
24
- * @param options.context - Optional context object.
25
- * @param options.context.appFetch - Optional custom fetch function to use instead of the global `fetch`.
26
- * @returns A promise resolving to an object containing an array of JWKs.
27
- * @throws Will throw an error if the JWKS retrieval fails.
27
+ * @param jwksUri - The JWKS URI.
28
+ * @param fetchFn - The fetch function to use.
29
+ * @returns An array of JWKs.
30
+ */
31
+ const fetchJwksFromUri = async (
32
+ jwksUri: string,
33
+ appFetch: GlobalFetch["fetch"]
34
+ ): Promise<JWK[]> => {
35
+ const jwks = await appFetch(jwksUri, {
36
+ method: "GET",
37
+ })
38
+ .then(hasStatusOrThrow(200))
39
+ .then((raw) => raw.json())
40
+ .then((json) => (json.jwks ? JWKS.parse(json.jwks) : JWKS.parse(json)));
41
+ return jwks.keys;
42
+ };
43
+
44
+ /**
45
+ * Retrieves JWKS when the client ID scheme includes x509 SAN DNS.
46
+ *
47
+ * @param decodedJwt - The decoded JWT.
48
+ * @param fetchFn - The fetch function to use.
49
+ * @returns An array of JWKs.
50
+ * @throws Will throw an error if no suitable keys are found.
51
+ */
52
+ const getJwksFromX509Cert = async (certChain: string[]): Promise<JWK[]> => {
53
+ if (!Array.isArray(certChain) || certChain.length === 0 || !certChain[0]) {
54
+ throw new NoSuitableKeysFoundInEntityConfiguration(
55
+ "No RP encrypt key found!"
56
+ );
57
+ }
58
+
59
+ const pemCert = convertCertToPem(certChain[0]);
60
+ const publicKey = parsePublicKey(pemCert);
61
+ if (!publicKey) {
62
+ throw new NoSuitableKeysFoundInEntityConfiguration(
63
+ "Unsupported public key type."
64
+ );
65
+ }
66
+ const signingJwk = getSigningJwk(publicKey);
67
+
68
+ return [signingJwk];
69
+ };
70
+
71
+ /**
72
+ * Constructs the well-known JWKS URL based on the issuer claim.
73
+ *
74
+ * @param issuer - The issuer URL.
75
+ * @returns The well-known JWKS URL.
76
+ */
77
+ const constructWellKnownJwksUrl = (issuer: string): string => {
78
+ const issuerUrl = new URL(issuer);
79
+ return new URL(
80
+ `/.well-known/jar-issuer${issuerUrl.pathname}`,
81
+ `${issuerUrl.protocol}//${issuerUrl.host}`
82
+ ).toString();
83
+ };
84
+
85
+ /**
86
+ * Fetches the JSON Web Key Set (JWKS) based on the provided Request Object encoded as a JWT.
87
+ * The retrieval process follows these steps in order:
88
+ *
89
+ * 1. **Direct JWK Retrieval**: If the JWT's protected header contains a `jwk` attribute, it uses this key directly.
90
+ * 2. **X.509 Certificate Retrieval**: If the protected header includes an `x5c` attribute, it extracts the JWKs from the provided X.509 certificate chain.
91
+ * 3. **Issuer's Well-Known Endpoint**: If neither `jwk` nor `x5c` are present, it constructs the JWKS URL using the issuer (`iss`) claim and fetches the keys from the issuer's well-known JWKS endpoint.
92
+ *
93
+ * The JWKS URL is constructed in the format `{issUrl.base}/.well-known/jar-issuer${issUrl.path}`,
94
+ * as detailed in the SD-JWT VC issuer metadata specification.
95
+ *
96
+ * @param requestObjectEncodedJwt - The Request Object encoded as a JWT.
97
+ * @param options - Optional parameters for fetching the JWKS.
98
+ * @param options.context - Optional context providing a custom fetch implementation.
99
+ * @param options.context.appFetch - A custom fetch function to replace the global `fetch` if provided.
100
+ * @returns A promise that resolves to an object containing an array of JSON Web Keys (JWKs).
101
+ * @throws {NoSuitableKeysFoundInEntityConfiguration} Throws an error if JWKS retrieval or key extraction fails.
28
102
  */
29
103
  export const fetchJwksFromRequestObject: FetchJwks<
30
104
  [string, { context?: { appFetch?: GlobalFetch["fetch"] } }?]
31
105
  > = async (requestObjectEncodedJwt, { context = {} } = {}) => {
32
106
  const { appFetch = fetch } = context;
33
107
  const requestObjectJwt = decodeJwt(requestObjectEncodedJwt);
108
+ const jwks: JWK[] = [];
34
109
 
35
110
  // 1. check if request object jwt contains the 'jwk' attribute
36
111
  if (requestObjectJwt.protectedHeader?.jwk) {
37
- return {
38
- keys: [JWK.parse(requestObjectJwt.protectedHeader.jwk)],
39
- };
112
+ const keys = [JWK.parse(requestObjectJwt.protectedHeader.jwk)];
113
+ jwks.push(...keys);
114
+ }
115
+
116
+ // 2. check if request object jwt contains the 'x5c' attribute
117
+ if (requestObjectJwt.protectedHeader.x5c) {
118
+ const keys = await getJwksFromX509Cert(
119
+ requestObjectJwt.protectedHeader.x5c
120
+ );
121
+ jwks.push(...keys);
122
+ }
123
+
124
+ // 3. check if client_metadata contains the 'jwks' or 'jwks_uri' attribute
125
+ const requestObject = RequestObject.parse(requestObjectJwt.payload);
126
+ const { client_metadata } = requestObject;
127
+
128
+ if (client_metadata?.jwks_uri) {
129
+ const fetchedJwks = await fetchJwksFromUri(
130
+ new URL(client_metadata.jwks_uri).toString(),
131
+ appFetch
132
+ );
133
+ jwks.push(...fetchedJwks);
134
+ }
135
+
136
+ if (client_metadata?.jwks) {
137
+ jwks.push(...client_metadata.jwks.keys);
138
+ }
139
+
140
+ // 3. According to Potential profile, retrieve from RP endpoint using iss claim
141
+ const issuer = requestObjectJwt.payload?.iss;
142
+ if (jwks.length === 0 && typeof issuer === "string") {
143
+ const wellKnownJwksUrl = constructWellKnownJwksUrl(issuer);
144
+ const jwksKeys = await fetchJwksFromUri(wellKnownJwksUrl, appFetch);
145
+ jwks.push(...jwksKeys);
40
146
  }
41
147
 
42
- // 2. According to Potential profile, retrieve from RP endpoint using iss claim
43
- const issClaimValue = requestObjectJwt.payload?.iss as string;
44
- if (issClaimValue) {
45
- const issUrl = new URL(issClaimValue);
46
- const wellKnownUrl = new URL(
47
- `/.well-known/jar-issuer${issUrl.pathname}`,
48
- `${issUrl.protocol}//${issUrl.host}`
49
- ).toString();
50
-
51
- // Fetches the JWKS from a specific endpoint of the entity's well-known configuration
52
- const jwks = await appFetch(wellKnownUrl, {
53
- method: "GET",
54
- })
55
- .then(hasStatusOrThrow(200))
56
- .then((raw) => raw.json())
57
- .then((json) => JWKS.parse(json.jwks));
58
-
59
- return {
60
- keys: jwks.keys,
61
- };
148
+ if (jwks.length === 0) {
149
+ throw new NoSuitableKeysFoundInEntityConfiguration(
150
+ "Request Object signature verification"
151
+ );
62
152
  }
63
153
 
64
- throw new NoSuitableKeysFoundInEntityConfiguration(
65
- "Request Object signature verification"
66
- );
154
+ return { keys: jwks };
67
155
  };
68
156
 
69
157
  /**
@@ -15,9 +15,10 @@ export const verifyRequestObjectSignature: VerifyRequestObjectSignature =
15
15
  const requestObjectJwt = decodeJwt(requestObjectEncodedJwt);
16
16
 
17
17
  // verify token signature to ensure the request object is authentic
18
- const pubKey = jwkKeys?.find(
19
- ({ kid }) => kid === requestObjectJwt.protectedHeader.kid
20
- );
18
+ const pubKey =
19
+ jwkKeys?.find(
20
+ ({ kid }) => kid === requestObjectJwt.protectedHeader.kid
21
+ ) || jwkKeys?.find(({ use }) => use === "sig");
21
22
 
22
23
  if (!pubKey) {
23
24
  throw new UnverifiedEntityError("Request Object signature verification!");
@@ -9,6 +9,7 @@ const INDEX_CLAIM_NAME = 1;
9
9
  export type EvaluatedDisclosures = {
10
10
  requiredDisclosures: DisclosureWithEncoded[];
11
11
  optionalDisclosures: DisclosureWithEncoded[];
12
+ unrequestedDisclosures: DisclosureWithEncoded[];
12
13
  };
13
14
 
14
15
  export type EvaluateInputDescriptorSdJwt4VC = (
@@ -99,8 +100,8 @@ const extractClaimName = (path: string): string | undefined => {
99
100
  * - Validates whether required fields are present (unless marked optional)
100
101
  * and match any specified JSONPath.
101
102
  * - If a field includes a JSON Schema filter, validates the claim value against that schema.
102
- * - Enforces `limit_disclosure` rules by returning only disclosures matching the specified fields
103
- * if set to "required". Otherwise return the array of all disclosures.
103
+ * - Enforces `limit_disclosure` rules by returning only disclosures, required and optional, matching the specified fields
104
+ * if set to "required". Otherwise also return the array unrequestedDisclosures with disclosures which can be passed for a particular use case.
104
105
  * - Throws an error if a required field is invalid or missing.
105
106
  *
106
107
  * @param inputDescriptor - Describes constraints (fields, filters, etc.) that must be satisfied.
@@ -115,7 +116,8 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
115
116
  // No validation, all field are optional
116
117
  return {
117
118
  requiredDisclosures: [],
118
- optionalDisclosures: disclosures,
119
+ optionalDisclosures: [],
120
+ unrequestedDisclosures: disclosures,
119
121
  };
120
122
  }
121
123
  const requiredClaimNames: string[] = [];
@@ -182,9 +184,6 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
182
184
  }
183
185
 
184
186
  // Categorizes disclosures into required and optional based on claim names and disclosure constraints.
185
- const isNotLimitDisclosure = !(
186
- inputDescriptor.constraints.limit_disclosure === "required"
187
- );
188
187
 
189
188
  const requiredDisclosures = disclosures.filter((disclosure) =>
190
189
  requiredClaimNames.includes(disclosure.decoded[INDEX_CLAIM_NAME])
@@ -197,8 +196,23 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
197
196
  !requiredClaimNames.includes(disclosure.decoded[INDEX_CLAIM_NAME]))
198
197
  );
199
198
 
199
+ const isNotLimitDisclosure = !(
200
+ inputDescriptor.constraints.limit_disclosure === "required"
201
+ );
202
+
203
+ const unrequestedDisclosures = isNotLimitDisclosure
204
+ ? disclosures.filter(
205
+ (disclosure) =>
206
+ !optionalClaimNames.includes(
207
+ disclosure.decoded[INDEX_CLAIM_NAME]
208
+ ) &&
209
+ !requiredClaimNames.includes(disclosure.decoded[INDEX_CLAIM_NAME])
210
+ )
211
+ : [];
212
+
200
213
  return {
201
214
  requiredDisclosures,
202
215
  optionalDisclosures,
216
+ unrequestedDisclosures,
203
217
  };
204
218
  };
@@ -6,12 +6,12 @@ import {
6
6
  import uuid from "react-native-uuid";
7
7
  import type { FetchJwks } from "./04-retrieve-rp-jwks";
8
8
  import type { VerifyRequestObjectSignature } from "./05-verify-request-object";
9
- import type { JWK } from "@pagopa/io-react-native-jwt/lib/typescript/types";
10
9
  import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
11
10
  import { hasStatusOrThrow, type Out } from "../../utils/misc";
12
11
  import { disclose } from "../../sd-jwt";
13
12
  import { PresentationDefinition, type Presentation } from "./types";
14
13
  import * as z from "zod";
14
+ import type { JWK } from "../../utils/jwk";
15
15
 
16
16
  export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
17
17
  export const AuthorizationResponse = z.object({
@@ -27,27 +27,25 @@ export const AuthorizationResponse = z.object({
27
27
  });
28
28
 
29
29
  /**
30
- * Selects an RSA public key (with `use = enc` and `kty = RSA`) from the set of JWK keys
30
+ * Selects a public key (with `use = enc`) from the set of JWK keys
31
31
  * offered by the Relying Party (RP) for encryption.
32
32
  *
33
33
  * @param rpJwkKeys - The array of JWKs retrieved from the RP entity configuration.
34
- * @returns The first suitable RSA public key found in the list.
35
- * @throws {NoSuitableKeysFoundInEntityConfiguration} If no suitable RSA encryption key is found.
34
+ * @returns The first suitable public key found in the list.
35
+ * @throws {NoSuitableKeysFoundInEntityConfiguration} If no suitable encryption key is found.
36
36
  */
37
- export const chooseRSAPublicKeyToEncrypt = (
37
+ export const choosePublicKeyToEncrypt = (
38
38
  rpJwkKeys: Out<FetchJwks>["keys"]
39
39
  ): JWK => {
40
- const [rsaEncKey] = rpJwkKeys.filter(
41
- (jwk) => jwk.use === "enc" && jwk.kty === "RSA"
42
- );
40
+ const [encKey] = rpJwkKeys.filter((jwk) => jwk.use === "enc");
43
41
 
44
- if (rsaEncKey) {
45
- return rsaEncKey;
42
+ if (encKey) {
43
+ return encKey;
46
44
  }
47
45
 
48
46
  // No suitable key found
49
47
  throw new NoSuitableKeysFoundInEntityConfiguration(
50
- "No suitable RSA public key found for encryption."
48
+ "No suitable public key found for encryption."
51
49
  );
52
50
  };
53
51
 
@@ -169,17 +167,27 @@ export const buildDirectPostJwtBody = async (
169
167
  });
170
168
 
171
169
  // Choose a suitable RSA public key for encryption
172
- const rsaPublicJwk = chooseRSAPublicKeyToEncrypt(jwkKeys);
170
+ const encPublicJwk = choosePublicKeyToEncrypt(jwkKeys);
173
171
 
174
172
  // Encrypt the authorization payload
173
+ const { client_metadata } = requestObject;
175
174
  const encryptedResponse = await new EncryptJwe(authzResponsePayload, {
176
- alg: "RSA-OAEP-256",
177
- enc: "A256CBC-HS512",
178
- kid: rsaPublicJwk.kid,
179
- }).encrypt(rsaPublicJwk);
175
+ alg:
176
+ (client_metadata?.authorization_encrypted_response_alg as
177
+ | "RSA-OAEP-256"
178
+ | "RSA-OAEP") || "RSA-OAEP-256",
179
+ enc:
180
+ (client_metadata?.authorization_encrypted_response_enc as
181
+ | "A256CBC-HS512"
182
+ | "A128CBC-HS256") || "A256CBC-HS512",
183
+ kid: encPublicJwk.kid,
184
+ }).encrypt(encPublicJwk);
180
185
 
181
186
  // Build the x-www-form-urlencoded form body
182
- const formBody = new URLSearchParams({ response: encryptedResponse });
187
+ const formBody = new URLSearchParams({
188
+ response: encryptedResponse,
189
+ state: requestObject.state,
190
+ });
183
191
  return formBody.toString();
184
192
  };
185
193
 
@@ -29,8 +29,8 @@ sequenceDiagram
29
29
  <summary>Remote Presentation flow</summary>
30
30
 
31
31
  ```ts
32
- // Scan e retrive qr-code
33
- const qrcode = ...
32
+ // Scan e retrive qr-code, decode it and get its parameters
33
+ const {requestUri, clientId} = ...
34
34
 
35
35
  // Retrieve the integrity key tag from the store and create its context
36
36
  const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
@@ -55,7 +55,7 @@ const walletInstanceAttestation =
55
55
  });
56
56
 
57
57
  // Start the issuance flow
58
- const { requestURI, clientId } = Credential.Presentation.startFlowFromQR(qrcode);
58
+ const { requestURI, clientId } = Credential.Presentation.startFlowFromQR(requestUri, clientId);
59
59
 
60
60
  // If use trust federation: Evaluate issuer trust
61
61
  const { rpConf } = await Credential.Presentation.evaluateRelyingPartyTrust(clientId);
@@ -111,4 +111,4 @@ const { presentationDefinition } = await Credential.Presentation.fetchPresentDef
111
111
 
112
112
  ```
113
113
 
114
- </details>
114
+ </details>
@@ -40,22 +40,6 @@ export class NoSuitableKeysFoundInEntityConfiguration extends IoWalletError {
40
40
  }
41
41
  }
42
42
 
43
- /**
44
- * When a QR code is not valid.
45
- *
46
- */
47
- export class InvalidQRCodeError extends IoWalletError {
48
- code = "ERR_INVALID_QR_CODE";
49
-
50
- /**
51
- * @param detail A description of why the QR code is considered invalid.
52
- */
53
- constructor(detail: string) {
54
- const message = `QR code is not valid: ${detail}.`;
55
- super(message);
56
- }
57
- }
58
-
59
43
  /**
60
44
  * When the entity is unverified because the Relying Party is not trusted.
61
45
  *
@@ -1,6 +1,7 @@
1
1
  import type { CryptoContext } from "@pagopa/io-react-native-jwt";
2
2
  import { UnixTime } from "../../sd-jwt/types";
3
3
  import * as z from "zod";
4
+ import { JWKS } from "../../utils/jwk";
4
5
 
5
6
  /**
6
7
  * A pair that associate a tokenized Verified Credential with the claims presented or requested to present.
@@ -77,7 +78,15 @@ export const RequestObject = z.object({
77
78
  response_type: z.literal("vp_token"),
78
79
  response_mode: z.enum(["direct_post.jwt", "direct_post"]),
79
80
  client_id: z.string(),
80
- client_id_scheme: z.string(), // previous z.literal("entity_id"),
81
+ client_id_scheme: z.string().optional(), // previous z.literal("entity_id"),
82
+ client_metadata: z
83
+ .object({
84
+ authorization_encrypted_response_alg: z.string().optional(),
85
+ authorization_encrypted_response_enc: z.string().optional(),
86
+ jwks_uri: z.string().optional(),
87
+ jwks: JWKS.optional(),
88
+ })
89
+ .optional(), // previous z.literal("entity_id"),
81
90
  scope: z.string().optional(),
82
91
  presentation_definition: PresentationDefinition.optional(),
83
92
  });
@@ -7,10 +7,9 @@ import {
7
7
  EntityStatement,
8
8
  TrustAnchorEntityConfiguration,
9
9
  } from "./types";
10
- import { JWK } from "../../utils/jwk";
10
+ import { JWK, type JWTDecodeResult } from "../../utils/jwk";
11
11
  import { IoWalletError } from "../../utils/errors";
12
12
  import * as z from "zod";
13
- import type { JWTDecodeResult } from "@pagopa/io-react-native-jwt/lib/typescript/types";
14
13
  import { getSignedEntityConfiguration, getSignedEntityStatement } from ".";
15
14
 
16
15
  type ParsedToken = {
@@ -7,6 +7,8 @@ import {
7
7
  import uuid from "react-native-uuid";
8
8
  import { thumbprint, type CryptoContext } from "@pagopa/io-react-native-jwt";
9
9
  import { fixBase64EncodingOnKey } from "./jwk";
10
+ import { X509, KEYUTIL, RSAKey, KJUR } from "jsrsasign";
11
+ import { JWK } from "./jwk";
10
12
 
11
13
  /**
12
14
  * Create a CryptoContext bound to a key pair.
@@ -63,3 +65,44 @@ export const withEphemeralKey = async <R>(
63
65
  const ephemeralContext = createCryptoContextFor(keytag);
64
66
  return fn(ephemeralContext).finally(() => deleteKey(keytag));
65
67
  };
68
+
69
+ /**
70
+ * Converts a certificate string to PEM format.
71
+ *
72
+ * @param certificate - The certificate string.
73
+ * @returns The PEM-formatted certificate.
74
+ */
75
+ export const convertCertToPem = (certificate: string): string =>
76
+ `-----BEGIN CERTIFICATE-----\n${certificate}\n-----END CERTIFICATE-----`;
77
+
78
+ /**
79
+ * Parses the public key from a PEM-formatted certificate.
80
+ *
81
+ * @param pemCert - The PEM-formatted certificate.
82
+ * @returns The public key object.
83
+ * @throws Will throw an error if the public key is unsupported.
84
+ */
85
+ export const parsePublicKey = (
86
+ pemCert: string
87
+ ): RSAKey | KJUR.crypto.ECDSA | undefined => {
88
+ const x509 = new X509();
89
+ x509.readCertPEM(pemCert);
90
+ const publicKey = x509.getPublicKey();
91
+
92
+ if (publicKey instanceof RSAKey || publicKey instanceof KJUR.crypto.ECDSA) {
93
+ return publicKey;
94
+ }
95
+
96
+ return undefined;
97
+ };
98
+
99
+ /**
100
+ * Retrieves the signing JWK from the public key.
101
+ *
102
+ * @param publicKey - The public key object.
103
+ * @returns The signing JWK.
104
+ */
105
+ export const getSigningJwk = (publicKey: RSAKey | KJUR.crypto.ECDSA): JWK => ({
106
+ ...JWK.parse(KEYUTIL.getJWKFromKey(publicKey)),
107
+ use: "sig",
108
+ });
@@ -1,6 +1,6 @@
1
1
  import { decode as decodeJwt } from "@pagopa/io-react-native-jwt";
2
- import type { JWTDecodeResult } from "@pagopa/io-react-native-jwt/lib/typescript/types";
3
2
  import { ValidationFailed } from "./errors";
3
+ import type { JWTDecodeResult } from "./jwk";
4
4
 
5
5
  /*
6
6
  * Decode a form_post.jwt and return the final JWT.
package/src/utils/jwk.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { removePadding } from "@pagopa/io-react-native-jwt";
1
+ import { decode, removePadding } from "@pagopa/io-react-native-jwt";
2
2
  import { z } from "zod";
3
3
 
4
4
  export type JWK = z.infer<typeof JWK>;
@@ -63,3 +63,5 @@ export type JWKS = z.infer<typeof JWKS>;
63
63
  export const JWKS = z.object({
64
64
  keys: z.array(JWK),
65
65
  });
66
+
67
+ export type JWTDecodeResult = ReturnType<typeof decode>;