@pagopa/io-react-native-wallet 2.0.0-next.1 → 2.0.0-next.3
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.
- package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js +2 -2
- package/lib/commonjs/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js +38 -24
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/05-authorize-access.js +6 -10
- package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +43 -11
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +51 -48
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/README.md +34 -13
- package/lib/commonjs/credential/issuance/const.js +1 -1
- package/lib/commonjs/credential/issuance/types.js +16 -10
- package/lib/commonjs/credential/issuance/types.js.map +1 -1
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js +2 -2
- package/lib/commonjs/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
- package/lib/commonjs/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +4 -4
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +3 -3
- package/lib/commonjs/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/commonjs/credential/status/README.md +0 -1
- package/lib/commonjs/sd-jwt/__test__/index.test.js +11 -15
- package/lib/commonjs/sd-jwt/__test__/index.test.js.map +1 -1
- package/lib/commonjs/sd-jwt/__test__/types.test.js +5 -2
- package/lib/commonjs/sd-jwt/__test__/types.test.js.map +1 -1
- package/lib/commonjs/sd-jwt/__test__/utils.test.js +37 -0
- package/lib/commonjs/sd-jwt/__test__/utils.test.js.map +1 -0
- package/lib/commonjs/sd-jwt/index.js +20 -0
- package/lib/commonjs/sd-jwt/index.js.map +1 -1
- package/lib/commonjs/sd-jwt/types.js +51 -4
- package/lib/commonjs/sd-jwt/types.js.map +1 -1
- package/lib/commonjs/sd-jwt/utils.js +64 -0
- package/lib/commonjs/sd-jwt/utils.js.map +1 -0
- package/lib/commonjs/trust/build-chain.js +252 -0
- package/lib/commonjs/trust/build-chain.js.map +1 -0
- package/lib/commonjs/trust/index.js +11 -282
- package/lib/commonjs/trust/index.js.map +1 -1
- package/lib/commonjs/trust/types.js +18 -13
- package/lib/commonjs/trust/types.js.map +1 -1
- package/lib/commonjs/trust/{chain.js → verify-chain.js} +40 -5
- package/lib/commonjs/trust/verify-chain.js.map +1 -0
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/par.js +32 -22
- package/lib/commonjs/utils/par.js.map +1 -1
- package/lib/commonjs/utils/pop.js +1 -1
- package/lib/commonjs/utils/pop.js.map +1 -1
- package/lib/commonjs/wallet-instance-attestation/types.js +5 -1
- package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
- package/lib/module/credential/issuance/02-evaluate-issuer-trust.js +1 -1
- package/lib/module/credential/issuance/02-evaluate-issuer-trust.js.map +1 -1
- package/lib/module/credential/issuance/03-start-user-authorization.js +38 -24
- package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/05-authorize-access.js +6 -10
- package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/module/credential/issuance/06-obtain-credential.js +44 -12
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js +51 -48
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/module/credential/issuance/README.md +34 -13
- package/lib/module/credential/issuance/const.js +1 -1
- package/lib/module/credential/issuance/types.js +12 -8
- package/lib/module/credential/issuance/types.js.map +1 -1
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js +1 -1
- package/lib/module/credential/presentation/02-evaluate-rp-trust.js.map +1 -1
- package/lib/module/credential/presentation/05-verify-request-object.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js +4 -4
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +3 -3
- package/lib/module/credential/presentation/08-send-authorization-response.js +1 -1
- package/lib/module/credential/presentation/08-send-authorization-response.js.map +1 -1
- package/lib/module/credential/status/README.md +0 -1
- package/lib/module/sd-jwt/__test__/index.test.js +11 -16
- package/lib/module/sd-jwt/__test__/index.test.js.map +1 -1
- package/lib/module/sd-jwt/__test__/types.test.js +5 -2
- package/lib/module/sd-jwt/__test__/types.test.js.map +1 -1
- package/lib/module/sd-jwt/__test__/utils.test.js +35 -0
- package/lib/module/sd-jwt/__test__/utils.test.js.map +1 -0
- package/lib/module/sd-jwt/index.js +1 -0
- package/lib/module/sd-jwt/index.js.map +1 -1
- package/lib/module/sd-jwt/types.js +50 -3
- package/lib/module/sd-jwt/types.js.map +1 -1
- package/lib/module/sd-jwt/utils.js +57 -0
- package/lib/module/sd-jwt/utils.js.map +1 -0
- package/lib/module/trust/build-chain.js +235 -0
- package/lib/module/trust/build-chain.js.map +1 -0
- package/lib/module/trust/index.js +5 -268
- package/lib/module/trust/index.js.map +1 -1
- package/lib/module/trust/types.js +18 -13
- package/lib/module/trust/types.js.map +1 -1
- package/lib/module/trust/{chain.js → verify-chain.js} +36 -2
- package/lib/module/trust/verify-chain.js.map +1 -0
- package/lib/module/utils/errors.js +1 -1
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/par.js +29 -20
- package/lib/module/utils/par.js.map +1 -1
- package/lib/module/utils/pop.js +1 -1
- package/lib/module/utils/pop.js.map +1 -1
- package/lib/module/wallet-instance-attestation/types.js +5 -1
- package/lib/module/wallet-instance-attestation/types.js.map +1 -1
- package/lib/typescript/client/generated/wallet-provider.d.ts +12 -12
- package/lib/typescript/credential/issuance/01-start-flow.d.ts +2 -2
- package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/02-evaluate-issuer-trust.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +7 -6
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +10 -5
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +3 -2
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/const.d.ts +1 -1
- package/lib/typescript/credential/issuance/types.d.ts +46 -26
- package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/02-evaluate-rp-trust.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/05-verify-request-object.d.ts +1 -1
- package/lib/typescript/credential/presentation/05-verify-request-object.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts +2 -2
- package/lib/typescript/credential/presentation/08-send-authorization-response.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/types.d.ts +4 -4
- package/lib/typescript/pid/sd-jwt/types.d.ts +7 -7
- package/lib/typescript/sd-jwt/__test__/utils.test.d.ts +2 -0
- package/lib/typescript/sd-jwt/__test__/utils.test.d.ts.map +1 -0
- package/lib/typescript/sd-jwt/index.d.ts +21 -8
- package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/types.d.ts +194 -12
- package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/utils.d.ts +18 -0
- package/lib/typescript/sd-jwt/utils.d.ts.map +1 -0
- package/lib/typescript/trust/build-chain.d.ts +1300 -0
- package/lib/typescript/trust/build-chain.d.ts.map +1 -0
- package/lib/typescript/trust/index.d.ts +5 -1301
- package/lib/typescript/trust/index.d.ts.map +1 -1
- package/lib/typescript/trust/types.d.ts +788 -624
- package/lib/typescript/trust/types.d.ts.map +1 -1
- package/lib/typescript/trust/{chain.d.ts → verify-chain.d.ts} +17 -1
- package/lib/typescript/trust/verify-chain.d.ts.map +1 -0
- package/lib/typescript/utils/errors.d.ts +2 -2
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/par.d.ts +29 -13
- package/lib/typescript/utils/par.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/types.d.ts +9 -9
- package/lib/typescript/wallet-instance-attestation/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/credential/issuance/01-start-flow.ts +2 -2
- package/src/credential/issuance/02-evaluate-issuer-trust.ts +1 -1
- package/src/credential/issuance/03-start-user-authorization.ts +57 -38
- package/src/credential/issuance/05-authorize-access.ts +5 -11
- package/src/credential/issuance/06-obtain-credential.ts +53 -23
- package/src/credential/issuance/07-verify-and-parse-credential.ts +54 -62
- package/src/credential/issuance/README.md +34 -13
- package/src/credential/issuance/const.ts +1 -1
- package/src/credential/issuance/types.ts +18 -8
- package/src/credential/presentation/02-evaluate-rp-trust.ts +1 -1
- package/src/credential/presentation/05-verify-request-object.ts +1 -1
- package/src/credential/presentation/07-evaluate-dcql-query.ts +4 -4
- package/src/credential/presentation/07-evaluate-input-descriptor.ts +3 -3
- package/src/credential/presentation/08-send-authorization-response.ts +4 -4
- package/src/credential/status/README.md +0 -1
- package/src/sd-jwt/__test__/index.test.ts +8 -29
- package/src/sd-jwt/__test__/types.test.ts +6 -2
- package/src/sd-jwt/__test__/utils.test.ts +37 -0
- package/src/sd-jwt/index.ts +2 -0
- package/src/sd-jwt/types.ts +49 -2
- package/src/sd-jwt/utils.ts +73 -0
- package/src/trust/build-chain.ts +395 -0
- package/src/trust/index.ts +5 -442
- package/src/trust/types.ts +23 -17
- package/src/trust/{chain.ts → verify-chain.ts} +41 -1
- package/src/utils/errors.ts +4 -4
- package/src/utils/par.ts +37 -21
- package/src/utils/pop.ts +1 -1
- package/src/wallet-instance-attestation/types.ts +3 -1
- package/lib/commonjs/trust/chain.js.map +0 -1
- package/lib/module/trust/chain.js.map +0 -1
- package/lib/typescript/trust/chain.d.ts.map +0 -1
@@ -14,7 +14,7 @@ import {
|
|
14
14
|
UnexpectedStatusCodeError,
|
15
15
|
ValidationFailed,
|
16
16
|
} from "../../utils/errors";
|
17
|
-
import { CredentialResponse } from "./types";
|
17
|
+
import { CredentialResponse, NonceResponse } from "./types";
|
18
18
|
import { createDPopToken } from "../../utils/dpop";
|
19
19
|
import { v4 as uuidv4 } from "uuid";
|
20
20
|
import { LogLevel, Logger } from "../../utils/logging";
|
@@ -23,14 +23,17 @@ export type ObtainCredential = (
|
|
23
23
|
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
24
24
|
accessToken: Out<AuthorizeAccess>["accessToken"],
|
25
25
|
clientId: Out<StartUserAuthorization>["clientId"],
|
26
|
-
credentialDefinition:
|
26
|
+
credentialDefinition: {
|
27
|
+
credential_configuration_id: string;
|
28
|
+
credential_identifier?: string;
|
29
|
+
},
|
27
30
|
context: {
|
28
31
|
dPopCryptoContext: CryptoContext;
|
29
32
|
credentialCryptoContext: CryptoContext;
|
30
33
|
appFetch?: GlobalFetch["fetch"];
|
31
34
|
},
|
32
35
|
operationType?: "reissuing"
|
33
|
-
) => Promise<
|
36
|
+
) => Promise<{ credential: string; format: string }>;
|
34
37
|
|
35
38
|
export const createNonceProof = async (
|
36
39
|
nonce: string,
|
@@ -63,11 +66,11 @@ export const createNonceProof = async (
|
|
63
66
|
* @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
|
64
67
|
* @param accessToken The access token response returned by {@link authorizeAccess}
|
65
68
|
* @param clientId The client id returned by {@link startUserAuthorization}
|
66
|
-
* @param credentialDefinition The credential definition of the credential to be obtained returned by {@link
|
67
|
-
* @param tokenRequestSignedDPop The DPoP signed token request returned by {@link authorizeAccess}
|
69
|
+
* @param credentialDefinition The credential definition of the credential to be obtained returned by {@link authorizeAccess}
|
68
70
|
* @param context.credentialCryptoContext The crypto context used to obtain the credential
|
69
71
|
* @param context.dPopCryptoContext The DPoP crypto context
|
70
72
|
* @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
|
73
|
+
* @param operationType Specify the type of credential issuance (used for reissuing)
|
71
74
|
* @returns The credential response containing the credential
|
72
75
|
*/
|
73
76
|
export const obtainCredential: ObtainCredential = async (
|
@@ -83,8 +86,21 @@ export const obtainCredential: ObtainCredential = async (
|
|
83
86
|
appFetch = fetch,
|
84
87
|
dPopCryptoContext,
|
85
88
|
} = context;
|
89
|
+
const { credential_configuration_id, credential_identifier } =
|
90
|
+
credentialDefinition;
|
86
91
|
|
87
92
|
const credentialUrl = issuerConf.openid_credential_issuer.credential_endpoint;
|
93
|
+
const issuerUrl = issuerConf.oauth_authorization_server.issuer;
|
94
|
+
const nonceUrl = issuerConf.openid_credential_issuer.nonce_endpoint;
|
95
|
+
|
96
|
+
// Fetch the nonce from the Credential Issuer
|
97
|
+
const { c_nonce } = await appFetch(nonceUrl, {
|
98
|
+
method: "POST",
|
99
|
+
headers: { "Content-Type": "application/json" },
|
100
|
+
})
|
101
|
+
.then(hasStatusOrThrow(200))
|
102
|
+
.then((res) => res.json())
|
103
|
+
.then((body) => NonceResponse.parse(body));
|
88
104
|
|
89
105
|
/**
|
90
106
|
* JWT proof token to bind the request nonce to the key that will bind the holder User with the Credential
|
@@ -92,9 +108,9 @@ export const obtainCredential: ObtainCredential = async (
|
|
92
108
|
* @see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-proof-types
|
93
109
|
*/
|
94
110
|
const signedNonceProof = await createNonceProof(
|
95
|
-
|
111
|
+
c_nonce,
|
96
112
|
clientId,
|
97
|
-
|
113
|
+
issuerUrl,
|
98
114
|
credentialCryptoContext
|
99
115
|
);
|
100
116
|
|
@@ -103,10 +119,10 @@ export const obtainCredential: ObtainCredential = async (
|
|
103
119
|
// Validation of accessTokenResponse.authorization_details if contain credentialDefinition
|
104
120
|
const containsCredentialDefinition = accessToken.authorization_details.some(
|
105
121
|
(c) =>
|
106
|
-
c.credential_configuration_id ===
|
107
|
-
|
108
|
-
|
109
|
-
|
122
|
+
c.credential_configuration_id === credential_configuration_id &&
|
123
|
+
(credential_identifier
|
124
|
+
? c.credential_identifiers.includes(credential_identifier)
|
125
|
+
: true)
|
110
126
|
);
|
111
127
|
|
112
128
|
if (!containsCredentialDefinition) {
|
@@ -120,17 +136,21 @@ export const obtainCredential: ObtainCredential = async (
|
|
120
136
|
});
|
121
137
|
}
|
122
138
|
|
123
|
-
/**
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
139
|
+
/**
|
140
|
+
* The credential request body.
|
141
|
+
* We accept both `credential_identifier` (recommended) and `credential_configuration_id`
|
142
|
+
* when the Authorization Server does not support `credential_identifier`.
|
143
|
+
* @see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-15.html#section-3.3.4
|
144
|
+
*/
|
145
|
+
const credentialRequestFormBody = credential_identifier
|
146
|
+
? {
|
147
|
+
credential_identifier: credential_identifier,
|
148
|
+
proof: { jwt: signedNonceProof, proof_type: "jwt" },
|
149
|
+
}
|
150
|
+
: {
|
151
|
+
credential_configuration_id: credential_configuration_id,
|
152
|
+
proof: { jwt: signedNonceProof, proof_type: "jwt" },
|
153
|
+
};
|
134
154
|
|
135
155
|
Logger.log(
|
136
156
|
LogLevel.DEBUG,
|
@@ -180,7 +200,17 @@ export const obtainCredential: ObtainCredential = async (
|
|
180
200
|
`Credential Response: ${JSON.stringify(credentialRes.data)}`
|
181
201
|
);
|
182
202
|
|
183
|
-
|
203
|
+
// Extract the format corresponding to the credential_configuration_id used
|
204
|
+
const issuerCredentialConfig =
|
205
|
+
issuerConf.openid_credential_issuer.credential_configurations_supported[
|
206
|
+
credential_configuration_id
|
207
|
+
];
|
208
|
+
|
209
|
+
// TODO: [SIW-2264] Handle multiple credentials
|
210
|
+
return {
|
211
|
+
credential: credentialRes.data.credentials.at(0)!.credential,
|
212
|
+
format: issuerCredentialConfig!.format,
|
213
|
+
};
|
184
214
|
};
|
185
215
|
|
186
216
|
/**
|
@@ -9,10 +9,14 @@ import type { JWK } from "../../utils/jwk";
|
|
9
9
|
import type { ObtainCredential } from "./06-obtain-credential";
|
10
10
|
import { LogLevel, Logger } from "../../utils/logging";
|
11
11
|
|
12
|
+
type IssuerConf = Out<EvaluateIssuerTrust>["issuerConf"];
|
13
|
+
type CredentialConf =
|
14
|
+
IssuerConf["openid_credential_issuer"]["credential_configurations_supported"][string];
|
15
|
+
|
12
16
|
export type VerifyAndParseCredential = (
|
13
|
-
issuerConf:
|
17
|
+
issuerConf: IssuerConf,
|
14
18
|
credential: Out<ObtainCredential>["credential"],
|
15
|
-
|
19
|
+
credentialConfigurationId: string,
|
16
20
|
context: {
|
17
21
|
credentialCryptoContext: CryptoContext;
|
18
22
|
/**
|
@@ -54,54 +58,35 @@ type DecodedSdJwtCredential = Out<typeof verifySdJwt> & {
|
|
54
58
|
};
|
55
59
|
|
56
60
|
const parseCredentialSdJwt = (
|
57
|
-
//
|
58
|
-
|
61
|
+
// The credential configuration to use to parse the provided credential
|
62
|
+
credentialConfig: CredentialConf,
|
59
63
|
{ sdJwt, disclosures }: DecodedSdJwtCredential,
|
60
64
|
ignoreMissingAttributes: boolean = false,
|
61
65
|
includeUndefinedAttributes: boolean = false
|
62
66
|
): ParsedCredential => {
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
LogLevel.ERROR,
|
68
|
-
`Credential type not supported by the issuer: ${sdJwt.payload.vct}`
|
69
|
-
);
|
70
|
-
throw new IoWalletError("Credential type not supported by the issuer");
|
67
|
+
if (credentialConfig.format !== sdJwt.header.typ) {
|
68
|
+
const message = `Received credential is of an unknwown type. Expected one of [${credentialConfig.format}], received '${sdJwt.header.typ}'`;
|
69
|
+
Logger.log(LogLevel.ERROR, message);
|
70
|
+
throw new IoWalletError(message);
|
71
71
|
}
|
72
72
|
|
73
|
-
if (
|
74
|
-
Logger.log(
|
75
|
-
LogLevel.ERROR,
|
76
|
-
`Received credential is of an unknwown type. Expected one of [${credentialSubject.format}], received '${sdJwt.header.typ}'`
|
77
|
-
);
|
78
|
-
throw new IoWalletError(
|
79
|
-
`Received credential is of an unknwown type. Expected one of [${credentialSubject.format}], received '${sdJwt.header.typ}', `
|
80
|
-
);
|
81
|
-
}
|
82
|
-
|
83
|
-
// transfrom a record { key: value } in an iterable of pairs [key, value]
|
84
|
-
if (!credentialSubject.claims) {
|
73
|
+
if (!credentialConfig.claims) {
|
85
74
|
Logger.log(LogLevel.ERROR, "Missing claims in the credential subject");
|
86
75
|
throw new IoWalletError("Missing claims in the credential subject"); // TODO [SIW-1268]: should not be optional
|
87
76
|
}
|
88
|
-
const attrDefinitions =
|
77
|
+
const attrDefinitions = credentialConfig.claims;
|
89
78
|
|
90
79
|
// the key of the attribute defintion must match the disclosure's name
|
91
80
|
const attrsNotInDisclosures = attrDefinitions.filter(
|
92
|
-
(
|
81
|
+
(definition) => !disclosures.some(([, name]) => name === definition.path[0]) // Ignore nested paths for now, see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-15.html#name-claims-path-pointer
|
93
82
|
);
|
94
83
|
if (attrsNotInDisclosures.length > 0) {
|
95
|
-
const missing = attrsNotInDisclosures.map((_) => _[0
|
84
|
+
const missing = attrsNotInDisclosures.map((_) => _.path[0]).join(", ");
|
96
85
|
const received = disclosures.map((_) => _[1 /* name */]).join(", ");
|
97
86
|
if (!ignoreMissingAttributes) {
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
);
|
102
|
-
throw new IoWalletError(
|
103
|
-
`Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`
|
104
|
-
);
|
87
|
+
const message = `Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`;
|
88
|
+
Logger.log(LogLevel.ERROR, message);
|
89
|
+
throw new IoWalletError(message);
|
105
90
|
}
|
106
91
|
}
|
107
92
|
|
@@ -111,13 +96,13 @@ const parseCredentialSdJwt = (
|
|
111
96
|
attrDefinitions
|
112
97
|
// retrieve the value from the disclosure set
|
113
98
|
.map(
|
114
|
-
(
|
99
|
+
({ path, ...definition }) =>
|
115
100
|
[
|
116
|
-
|
101
|
+
path[0],
|
117
102
|
{
|
118
103
|
...definition,
|
119
104
|
value: disclosures.find(
|
120
|
-
(_) => _[1 /* name */] ===
|
105
|
+
(_) => _[1 /* name */] === path[0]
|
121
106
|
)?.[2 /* value */],
|
122
107
|
},
|
123
108
|
] as const
|
@@ -186,30 +171,18 @@ async function verifyCredentialSdJwt(
|
|
186
171
|
const { cnf } = decodedCredential.sdJwt.payload;
|
187
172
|
|
188
173
|
if (!cnf.jwk.kid || cnf.jwk.kid !== holderBindingKey.kid) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
);
|
193
|
-
throw new IoWalletError(
|
194
|
-
`Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`
|
195
|
-
);
|
174
|
+
const message = `Failed to verify holder binding, expected kid: ${holderBindingKey.kid}, got: ${decodedCredential.sdJwt.payload.cnf.jwk.kid}`;
|
175
|
+
Logger.log(LogLevel.ERROR, message);
|
176
|
+
throw new IoWalletError(message);
|
196
177
|
}
|
197
178
|
|
198
179
|
return decodedCredential;
|
199
180
|
}
|
200
181
|
|
201
|
-
|
202
|
-
type WithFormat<Format extends Parameters<VerifyAndParseCredential>[2]> = (
|
203
|
-
_0: Parameters<VerifyAndParseCredential>[0],
|
204
|
-
_1: Parameters<VerifyAndParseCredential>[1],
|
205
|
-
_2: Format,
|
206
|
-
_3: Parameters<VerifyAndParseCredential>[3]
|
207
|
-
) => ReturnType<VerifyAndParseCredential>;
|
208
|
-
|
209
|
-
const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
182
|
+
const verifyAndParseCredentialSdJwt: VerifyAndParseCredential = async (
|
210
183
|
issuerConf,
|
211
184
|
credential,
|
212
|
-
|
185
|
+
credentialConfigurationId,
|
213
186
|
{
|
214
187
|
credentialCryptoContext,
|
215
188
|
ignoreMissingAttributes,
|
@@ -224,8 +197,21 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
|
224
197
|
|
225
198
|
Logger.log(LogLevel.DEBUG, `Decoded credential: ${JSON.stringify(decoded)}`);
|
226
199
|
|
200
|
+
const credentialConfig =
|
201
|
+
issuerConf.openid_credential_issuer.credential_configurations_supported[
|
202
|
+
credentialConfigurationId
|
203
|
+
];
|
204
|
+
|
205
|
+
if (!credentialConfig) {
|
206
|
+
Logger.log(
|
207
|
+
LogLevel.ERROR,
|
208
|
+
`Credential type not supported by the issuer: ${credentialConfigurationId}`
|
209
|
+
);
|
210
|
+
throw new IoWalletError("Credential type not supported by the issuer");
|
211
|
+
}
|
212
|
+
|
227
213
|
const parsedCredential = parseCredentialSdJwt(
|
228
|
-
|
214
|
+
credentialConfig,
|
229
215
|
decoded,
|
230
216
|
ignoreMissingAttributes,
|
231
217
|
includeUndefinedAttributes
|
@@ -251,7 +237,7 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
|
251
237
|
* Verify and parse an encoded credential.
|
252
238
|
* @param issuerConf The Issuer configuration returned by {@link evaluateIssuerTrust}
|
253
239
|
* @param credential The encoded credential returned by {@link obtainCredential}
|
254
|
-
* @param
|
240
|
+
* @param credentialConfigurationId The credential configuration ID that defines the provided credential
|
255
241
|
* @param context.credentialCryptoContext The crypto context used to obtain the credential in {@link obtainCredential}
|
256
242
|
* @param context.ignoreMissingAttributes Skip error when attributes declared in the issuer configuration are not found within disclosures
|
257
243
|
* @param context.includeUndefinedAttributes Include attributes not explicitly declared in the issuer configuration
|
@@ -263,19 +249,25 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
|
263
249
|
export const verifyAndParseCredential: VerifyAndParseCredential = async (
|
264
250
|
issuerConf,
|
265
251
|
credential,
|
266
|
-
|
252
|
+
credentialConfigurationId,
|
267
253
|
context
|
268
254
|
) => {
|
269
|
-
|
270
|
-
|
255
|
+
const format =
|
256
|
+
issuerConf.openid_credential_issuer.credential_configurations_supported[
|
257
|
+
credentialConfigurationId
|
258
|
+
]?.format;
|
259
|
+
|
260
|
+
if (format === "dc+sd-jwt") {
|
261
|
+
Logger.log(LogLevel.DEBUG, "Parsing credential in dc+sd-jwt format");
|
271
262
|
return verifyAndParseCredentialSdJwt(
|
272
263
|
issuerConf,
|
273
264
|
credential,
|
274
|
-
|
265
|
+
credentialConfigurationId,
|
275
266
|
context
|
276
267
|
);
|
277
268
|
}
|
278
269
|
|
279
|
-
|
280
|
-
|
270
|
+
const message = `Unsupported credential format: ${format}`;
|
271
|
+
Logger.log(LogLevel.ERROR, message);
|
272
|
+
throw new IoWalletError(message);
|
281
273
|
};
|
@@ -6,7 +6,7 @@ There's a fork in the flow which is based on the type of the credential that is
|
|
6
6
|
This is due to the fact that eID credentials require a different authorization flow than other credentials, which is accomplished by a strong authentication method like SPID or CIE.
|
7
7
|
Credentials instead require a simpler authorization flow and they require other credentials to be presented in order to be issued.
|
8
8
|
|
9
|
-
The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step.
|
9
|
+
The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step. Available credentials are identified with a unique `credential_configuration_id`, that must be used when requesting authorization. The Authorization Server returns an array of **credential identifiers** that map to the `credential_configuration_id` provided: to obtain the credential, one of the credential identifiers (or all of them) must be requested to the credential endpoint.
|
10
10
|
|
11
11
|
## Sequence Diagram
|
12
12
|
|
@@ -72,6 +72,8 @@ The expected result from the authentication process is in `form_post.jwt` format
|
|
72
72
|
<summary>Credential issuance flow</summary>
|
73
73
|
|
74
74
|
```ts
|
75
|
+
// TODO: [SIW-2209] update documentation in PR #219
|
76
|
+
|
75
77
|
// Retrieve the integrity key tag from the store and create its context
|
76
78
|
const integrityKeyTag = "example"; // Let's assume this is the key tag used to create the wallet instance
|
77
79
|
const integrityContext = getIntegrityContext(integrityKeyTag);
|
@@ -251,11 +253,10 @@ const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
|
|
251
253
|
// Start the issuance flow
|
252
254
|
const startFlow: Credential.Issuance.StartFlow = () => ({
|
253
255
|
issuerUrl: WALLET_EID_PROVIDER_BASE_URL,
|
254
|
-
|
255
|
-
appFetch,
|
256
|
+
credentialId: "dc_sd_jwt_PersonIdentificationData",
|
256
257
|
});
|
257
258
|
|
258
|
-
const { issuerUrl } = startFlow();
|
259
|
+
const { issuerUrl, credentialId } = startFlow();
|
259
260
|
|
260
261
|
// Evaluate issuer trust
|
261
262
|
const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
|
@@ -265,12 +266,16 @@ const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
|
|
265
266
|
|
266
267
|
// Start user authorization
|
267
268
|
const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
|
268
|
-
await Credential.Issuance.startUserAuthorization(
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
269
|
+
await Credential.Issuance.startUserAuthorization(
|
270
|
+
issuerConf,
|
271
|
+
[credentialId], // Request authorization for one or more credentials
|
272
|
+
{
|
273
|
+
walletInstanceAttestation,
|
274
|
+
redirectUri,
|
275
|
+
wiaCryptoContext,
|
276
|
+
appFetch,
|
277
|
+
}
|
278
|
+
);
|
274
279
|
|
275
280
|
// Complete the authorization process with query mode with the authorizationContext which opens the browser
|
276
281
|
const { code } =
|
@@ -301,12 +306,27 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
|
|
301
306
|
}
|
302
307
|
);
|
303
308
|
|
309
|
+
|
310
|
+
const [pidCredentialDefinition] = credentialDefinition;
|
311
|
+
|
312
|
+
// Extract the credential_identifier(s) from the access token
|
313
|
+
// For each one of them, a credential can be obtained by calling `obtainCredential`
|
314
|
+
const { credential_configuration_id, credential_identifiers } =
|
315
|
+
accessToken.authorization_details.find(
|
316
|
+
(authDetails) =>
|
317
|
+
authDetails.credential_configuration_id ===
|
318
|
+
pidCredentialDefinition.credential_configuration_id
|
319
|
+
);
|
320
|
+
|
304
321
|
// Obtain che eID credential
|
305
322
|
const { credential, format } = await Credential.Issuance.obtainCredential(
|
306
323
|
issuerConf,
|
307
324
|
accessToken,
|
308
325
|
clientId,
|
309
|
-
|
326
|
+
{
|
327
|
+
credential_configuration_id,
|
328
|
+
credential_identifier: credential_identifiers.at(0),
|
329
|
+
},
|
310
330
|
{
|
311
331
|
credentialCryptoContext,
|
312
332
|
dPopCryptoContext,
|
@@ -318,15 +338,16 @@ const { credential, format } = await Credential.Issuance.obtainCredential(
|
|
318
338
|
const { parsedCredential, issuedAt, expiration } = await Credential.Issuance.verifyAndParseCredential(
|
319
339
|
issuerConf,
|
320
340
|
credential,
|
321
|
-
|
341
|
+
credential_configuration_id,
|
322
342
|
{ credentialCryptoContext }
|
323
343
|
);
|
324
344
|
|
325
345
|
return {
|
326
346
|
parsedCredential,
|
327
347
|
credential,
|
348
|
+
credentialConfigurationId: credential_configuration_id
|
349
|
+
credentialType: "PersonIdentificationData",
|
328
350
|
keyTag: credentialKeyTag,
|
329
|
-
credentialType,
|
330
351
|
issuedAt,
|
331
352
|
expiration
|
332
353
|
};
|
@@ -1,14 +1,17 @@
|
|
1
|
-
import { AuthorizationDetail } from "../../utils/par";
|
2
1
|
import * as z from "zod";
|
3
|
-
|
2
|
+
|
3
|
+
export type AuthorizationDetail = z.infer<typeof AuthorizationDetail>;
|
4
|
+
export const AuthorizationDetail = z.object({
|
5
|
+
type: z.literal("openid_credential"),
|
6
|
+
credential_configuration_id: z.string(),
|
7
|
+
credential_identifiers: z.array(z.string()),
|
8
|
+
});
|
4
9
|
|
5
10
|
export type TokenResponse = z.infer<typeof TokenResponse>;
|
6
11
|
|
7
12
|
export const TokenResponse = z.object({
|
8
13
|
access_token: z.string(),
|
9
14
|
authorization_details: z.array(AuthorizationDetail),
|
10
|
-
c_nonce: z.string(),
|
11
|
-
c_nonce_expires_in: z.number(),
|
12
15
|
expires_in: z.number(),
|
13
16
|
token_type: z.string(),
|
14
17
|
});
|
@@ -16,10 +19,12 @@ export const TokenResponse = z.object({
|
|
16
19
|
export type CredentialResponse = z.infer<typeof CredentialResponse>;
|
17
20
|
|
18
21
|
export const CredentialResponse = z.object({
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
credentials: z.array(
|
23
|
+
z.object({
|
24
|
+
credential: z.string(),
|
25
|
+
})
|
26
|
+
),
|
27
|
+
notification_id: z.string().optional(),
|
23
28
|
});
|
24
29
|
|
25
30
|
/**
|
@@ -30,3 +35,8 @@ export const ResponseUriResultShape = z.object({
|
|
30
35
|
});
|
31
36
|
|
32
37
|
export type ResponseMode = "query" | "form_post.jwt";
|
38
|
+
|
39
|
+
export type NonceResponse = z.infer<typeof NonceResponse>;
|
40
|
+
export const NonceResponse = z.object({
|
41
|
+
c_nonce: z.string(),
|
42
|
+
});
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import { getRelyingPartyEntityConfiguration } from "../../trust";
|
2
1
|
import { RelyingPartyEntityConfiguration } from "../../trust/types";
|
3
2
|
import type { StartFlow } from "../issuance/01-start-flow";
|
4
3
|
import type { Out } from "../../utils/misc";
|
4
|
+
import { getRelyingPartyEntityConfiguration } from "../../trust/build-chain";
|
5
5
|
|
6
6
|
export type EvaluateRelyingPartyTrust = (
|
7
7
|
rpUrl: Out<StartFlow>["issuerUrl"],
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { decode as decodeJwt, verify } from "@pagopa/io-react-native-jwt";
|
2
|
-
import type { RelyingPartyEntityConfiguration } from "../../trust";
|
3
2
|
import { InvalidRequestObjectError } from "./errors";
|
4
3
|
import { RequestObject } from "./types";
|
5
4
|
import { getJwksFromConfig } from "./04-retrieve-rp-jwks";
|
5
|
+
import type { RelyingPartyEntityConfiguration } from "../../trust/types";
|
6
6
|
|
7
7
|
export type VerifyRequestObject = (
|
8
8
|
requestObjectEncodedJwt: string,
|
@@ -56,7 +56,7 @@ const mapCredentialToObject = (jwt: string) => {
|
|
56
56
|
const credentialFormat = sdJwt.header.typ;
|
57
57
|
|
58
58
|
// TODO [SIW-2082]: support MDOC credentials
|
59
|
-
if (credentialFormat !== "
|
59
|
+
if (credentialFormat !== "dc+sd-jwt") {
|
60
60
|
throw new Error(`Unsupported credential format: ${credentialFormat}`);
|
61
61
|
}
|
62
62
|
|
@@ -100,7 +100,7 @@ const extractMissingCredentials = (
|
|
100
100
|
): NotFoundDetail[] => {
|
101
101
|
return getDcqlQueryFailedMatches(queryResult).map(([id]) => {
|
102
102
|
const credential = originalQuery.credentials.find((c) => c.id === id);
|
103
|
-
if (credential?.format !== "
|
103
|
+
if (credential?.format !== "dc+sd-jwt") {
|
104
104
|
throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
|
105
105
|
}
|
106
106
|
return { id, vctValues: credential.meta?.vct_values };
|
@@ -135,7 +135,7 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
|
|
135
135
|
);
|
136
136
|
|
137
137
|
return getDcqlQueryMatches(queryResult).map(([id, match]) => {
|
138
|
-
if (match.output.credential_format !== "
|
138
|
+
if (match.output.credential_format !== "dc+sd-jwt") {
|
139
139
|
throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
|
140
140
|
}
|
141
141
|
const { vct, claims } = match.output;
|
@@ -192,7 +192,7 @@ export const prepareRemotePresentations: PrepareRemotePresentations = async (
|
|
192
192
|
credentialId: item.id,
|
193
193
|
requestedClaims: item.requestedClaims,
|
194
194
|
vpToken: vp_token,
|
195
|
-
format: "
|
195
|
+
format: "dc+sd-jwt",
|
196
196
|
};
|
197
197
|
})
|
198
198
|
);
|
@@ -326,7 +326,7 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
|
|
326
326
|
|
327
327
|
return Promise.all(
|
328
328
|
inputDescriptors.map(async (descriptor) => {
|
329
|
-
if (descriptor.format?.["
|
329
|
+
if (descriptor.format?.["dc+sd-jwt"]) {
|
330
330
|
if (!decodedSdJwtCredentials.length) {
|
331
331
|
throw new CredentialsNotFoundError([
|
332
332
|
{
|
@@ -379,7 +379,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
|
|
379
379
|
credentialAndDescriptors.map(async (item) => {
|
380
380
|
const descriptor = item.inputDescriptor;
|
381
381
|
|
382
|
-
if (descriptor.format?.["
|
382
|
+
if (descriptor.format?.["dc+sd-jwt"]) {
|
383
383
|
const { vp_token } = await prepareVpToken(nonce, client_id, [
|
384
384
|
item.credential,
|
385
385
|
item.requestedClaims,
|
@@ -390,7 +390,7 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
|
|
390
390
|
requestedClaims: item.requestedClaims,
|
391
391
|
inputDescriptor: descriptor,
|
392
392
|
vpToken: vp_token,
|
393
|
-
format: "
|
393
|
+
format: "dc+sd-jwt",
|
394
394
|
};
|
395
395
|
}
|
396
396
|
|
@@ -1,24 +1,24 @@
|
|
1
1
|
import { EncryptJwe } from "@pagopa/io-react-native-jwt";
|
2
2
|
import uuid from "react-native-uuid";
|
3
|
-
import {
|
3
|
+
import { type FetchJwks, getJwksFromConfig } from "./04-retrieve-rp-jwks";
|
4
4
|
import type { VerifyRequestObject } from "./05-verify-request-object";
|
5
5
|
import { NoSuitableKeysFoundInEntityConfiguration } from "./errors";
|
6
6
|
import { hasStatusOrThrow, type Out } from "../../utils/misc";
|
7
7
|
import {
|
8
|
-
type RemotePresentation,
|
9
8
|
DirectAuthorizationBodyPayload,
|
10
9
|
ErrorResponse,
|
11
10
|
type LegacyRemotePresentation,
|
11
|
+
type RemotePresentation,
|
12
12
|
} from "./types";
|
13
13
|
import * as z from "zod";
|
14
14
|
import type { JWK } from "../../utils/jwk";
|
15
|
-
import type { RelyingPartyEntityConfiguration } from "../../trust";
|
16
15
|
import {
|
17
16
|
RelyingPartyResponseError,
|
17
|
+
RelyingPartyResponseErrorCodes,
|
18
18
|
ResponseErrorBuilder,
|
19
19
|
UnexpectedStatusCodeError,
|
20
|
-
RelyingPartyResponseErrorCodes,
|
21
20
|
} from "../../utils/errors";
|
21
|
+
import type { RelyingPartyEntityConfiguration } from "../../trust/types";
|
22
22
|
|
23
23
|
export type AuthorizationResponse = z.infer<typeof AuthorizationResponse>;
|
24
24
|
export const AuthorizationResponse = z.object({
|