From e7d33f1097eb4dfbb69ba49922520e84eec226bd Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 8 Nov 2024 13:45:13 -0800 Subject: [PATCH 01/15] add aip --- aips/aip-103.md | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 aips/aip-103.md diff --git a/aips/aip-103.md b/aips/aip-103.md new file mode 100644 index 00000000..7b4544b6 --- /dev/null +++ b/aips/aip-103.md @@ -0,0 +1,110 @@ +--- +aip: 103 +title: Enable interoperability for Federated Keyless Accounts for the same issuer (user-pool/tenant) +author: Oliver He (oliver.he@aptoslabs.com) +Status: Draft # | Last Call | Accepted | Final | Rejected> +last-call-end-date (*optional): +type: +created: 11/08/2024 +updated (*optional): +requires (*optional): https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-103.md +--- + +# AIP-103 - Enable interoperability for Federated Keyless Accounts for the same issuer (user-pool/tenant) + +## Summary + +This AIP proposes enabling Aptos Federated Keyless to be interoperable with dApps from the same issuer (user-pool/tenant). + +For IAM providers like Auth0 and Cognito, JWT tokens are scoped to a user-pool/tenant via the `iss` field, and they are also scoped to a specific application via the `aud` field. This means that JWTs from the same issuer but with different `aud` values are from different applications and cannot be used to derive the same Aptos Federated Keyless Account even though they represent the same user identity within the same user-pool/tenant. + +Many customers of Auth0 and Cognito have applications with different branding within the same user-pool/tenant ecosystem. Thus it is natural for such customers to use different application identifiers for their applications for organizational purposes. This AIP will enable Aptos Federated Keyless Accounts to be interoperable across such applications. + +## Impact and risks + +- The relaxation of the `aud` field will allow for broader interoperability across applications within the same user-pool/tenant. This allows for broader adoption of Aptos Federated Keyless Accounts in such user ecosystems. + +Risks +- Developers need to not use `aud`-less accounts when not appropriate. This can be mitigated by the Aptos SDK default behavior so that developers must explicitly enable using `aud`-less accounts. +- This introduces an additional proving path, one where the `aud` is not checked. It is important that such proofs are rejected if the account requires `aud` to be present, as encoded in the KeylessPublicKey. +- As circuit changes are needed to support `aud`-less accounts, a new ceremony will be needed to generate the proving key and verification key. +- We want such accounts to be limited to Federated Keyless Accounts, as constructing Keyless Accounts without aud checks is unsafe. This can be mitigated by the Aptos SDK disallowing `aud`-less accounts from being used as Keyless Accounts. The prover will also reject proof requests for Keyless providers (as of now Google and Apple). However, in a world where 3rd party provers are permitted, we cannot prevent developers from using `aud`-less accounts as Keyless Accounts, but developers would not have any incentive construct such accounts for their users (these accounts would be accessable by any other dApp, regardless of trust). +- The verification key will need an update, which will invalidate all existing proofs. Additionally the prover will need to start proving with the new proving key right away after the update. The prover has already been updated to support the proving key rotations and the SDK also supports state checks to invalidate old proofs. + +## Alternative solutions + +The alternative is to add an additional keyless public key type where the formula to compute the IdCommitment does not contain the `aud` at all. + +This is the advantage of explicit type safety as a completely new validation path would be implemented. + +However the drawbacks include: +- We need to add a new keyless public key type, which may not be needed if we can leverage the existing design. And avoiding proliferation of keyless public key types is desirable. +- Requiring imiplementation of a new authentication path in the authenticator, which may be error prone and takes additional engineering effort. +- Requires more complex changes to the prover as it would need to support a different public inputs hash calculation in order to differentiate between accounts with and without `aud`. Or it would need to use a different circuit versionentirely. + +Thus if we can leverage the existing design, it would be preferable to do so. + +## Specification and Implementation Details + +This AIP's implementation has three parts - + +1. We add an additional private input into the prover. This value will indicate whether the `aud` check is enabled. +- If it is enabled, the circuit will do the status quo set of verifications. +- If it is disabled, the circuit will use an empty `aud` value as a private input and skip checking the `aud` field. A valid JWT still needs to be provided and the public inputs hash calculation will still implicitly include the `aud` field via the `IdCommitment` in the `KeylessPublicKey`, but it will be set to the empty value. This means that proofs for `aud`-less accounts will be rejected if the account requires `aud` to be present, as the `IdCommitment` will be different. + +2. The prover API will also require an update to allow for indiciating whether the `aud` check is enabled. This will be done by adding a new boolean argument to the `prove` API. + +3. The SDK will also need to be updated to support instantiating of such accounts. This will require adding a new boolean argument to the `KeylessAccount` constructor and constructing the `KeylessPublicKey` and `AccountAddress` appropriately. + +## Testing (Optional) + +1. Write unit tests for the circuit to verify that it correctly handles the `aud` check. +2. Write unit tests for the SDK to verify that it correctly instantiates accounts with and without `aud` checks. +3. Do a manual end-to-end test in devnet/testnet via the SDK once the verification key is updated. +4. Write smoke tests ensuring that `aud`-less accounts are rejected if the account requires `aud` to be present. + +## Security Considerations + +The core security considerations are: +- Making sure the the circuit can securely support `aud`-less accounts. +- Making sure that such proofs are rejected if the account requires `aud` to be present (as encoded in the `KeylessPublicKey`s `IdCommitment`). + +## Future Potential + +This will allow onboarding more users into the Aptos blockchain via keyless accounts[^aip-61] and its extensions. + +## Timeline + +-Circuit changes: End of October 2024. +-Ceremony completion: End of November 2024. +-SDK update: by ceremony completion. +-Prover service update: by ceremony completion. +-Devnet verification key update: After ceremony completion. +-Devnet testing: After verification key update. Should take a few hours. +-Testnet verification key update: After devnet testing. +-Testnet testing: After testnet verification key update. +-Mainnet verification key update proposal: End of November 2024. +-Mainnet verification key update: A week after proposal submission. Estimated early December 2024. + +### Suggested implementation timeline + +See above. + +### Suggested developer platform support timeline + +Already supported via telegram. + +### Suggested deployment timeline + +See above. + +## References + +[^aip-61]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-61.md +[^aip-67]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-67.md +[^aip-75]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-75.md +[^aip-81]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-81.md +[^aip-61-recovery]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-61.md#recovery-service +[^jwks]: https://appleid.apple.com/.well-known/openid-configuration +[^passkeys]: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-66.md +[^ppid]: https://openid.net/specs/openid-connect-core-1_0.html#Terminology From abb720bde7c916fe795a0971cfe55146cfd30cb3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 8 Nov 2024 13:55:57 -0800 Subject: [PATCH 02/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 7b4544b6..fc4fc86b 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -35,7 +35,7 @@ Risks The alternative is to add an additional keyless public key type where the formula to compute the IdCommitment does not contain the `aud` at all. -This is the advantage of explicit type safety as a completely new validation path would be implemented. +This is the advantage of explicit type safety as a completely new validation path would be implemented. There would be no risk of such proofs being accepted for accounts that require `aud` to be present due to explicit differences in how the proof would be validated gated on the type of public key. However the drawbacks include: - We need to add a new keyless public key type, which may not be needed if we can leverage the existing design. And avoiding proliferation of keyless public key types is desirable. From 54cc372a350dad8455586640865875b53a10a8e5 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 21 Nov 2024 11:51:16 -0500 Subject: [PATCH 03/15] fix typos --- aips/aip-103.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index fc4fc86b..f73f9a15 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -28,19 +28,19 @@ Risks - Developers need to not use `aud`-less accounts when not appropriate. This can be mitigated by the Aptos SDK default behavior so that developers must explicitly enable using `aud`-less accounts. - This introduces an additional proving path, one where the `aud` is not checked. It is important that such proofs are rejected if the account requires `aud` to be present, as encoded in the KeylessPublicKey. - As circuit changes are needed to support `aud`-less accounts, a new ceremony will be needed to generate the proving key and verification key. -- We want such accounts to be limited to Federated Keyless Accounts, as constructing Keyless Accounts without aud checks is unsafe. This can be mitigated by the Aptos SDK disallowing `aud`-less accounts from being used as Keyless Accounts. The prover will also reject proof requests for Keyless providers (as of now Google and Apple). However, in a world where 3rd party provers are permitted, we cannot prevent developers from using `aud`-less accounts as Keyless Accounts, but developers would not have any incentive construct such accounts for their users (these accounts would be accessable by any other dApp, regardless of trust). +- We want such accounts to be limited to Federated Keyless Accounts, as constructing Keyless Accounts without aud checks is unsafe. This can be mitigated by the Aptos SDK disallowing `aud`-less accounts from being used as Keyless Accounts. The prover will also reject proof requests for Keyless providers (as of now Google and Apple). However, in a world where 3rd party provers are permitted, we cannot prevent developers from using `aud`-less accounts as Keyless Accounts, but developers would not have any incentive to construct such accounts for their users (these accounts would be accessable by any other dApp, regardless of trust). - The verification key will need an update, which will invalidate all existing proofs. Additionally the prover will need to start proving with the new proving key right away after the update. The prover has already been updated to support the proving key rotations and the SDK also supports state checks to invalidate old proofs. ## Alternative solutions The alternative is to add an additional keyless public key type where the formula to compute the IdCommitment does not contain the `aud` at all. -This is the advantage of explicit type safety as a completely new validation path would be implemented. There would be no risk of such proofs being accepted for accounts that require `aud` to be present due to explicit differences in how the proof would be validated gated on the type of public key. +This is the advantage of explicit type safety as a completely new validation path would be implemented. There would be no risk of such proofs being accepted for accounts that require `aud` to be present due to explicit differences in how the proof would be gated on the type of public key. However the drawbacks include: - We need to add a new keyless public key type, which may not be needed if we can leverage the existing design. And avoiding proliferation of keyless public key types is desirable. -- Requiring imiplementation of a new authentication path in the authenticator, which may be error prone and takes additional engineering effort. -- Requires more complex changes to the prover as it would need to support a different public inputs hash calculation in order to differentiate between accounts with and without `aud`. Or it would need to use a different circuit versionentirely. +- Requiring implementation of a new authentication path in the authenticator, which may be error prone and takes additional engineering effort. +- Requires more complex changes to the prover as it would need to support a different public inputs hash calculation in order to differentiate between accounts with and without `aud`. Or it would need to use a different circuit version entirely. Thus if we can leverage the existing design, it would be preferable to do so. @@ -50,7 +50,7 @@ This AIP's implementation has three parts - 1. We add an additional private input into the prover. This value will indicate whether the `aud` check is enabled. - If it is enabled, the circuit will do the status quo set of verifications. -- If it is disabled, the circuit will use an empty `aud` value as a private input and skip checking the `aud` field. A valid JWT still needs to be provided and the public inputs hash calculation will still implicitly include the `aud` field via the `IdCommitment` in the `KeylessPublicKey`, but it will be set to the empty value. This means that proofs for `aud`-less accounts will be rejected if the account requires `aud` to be present, as the `IdCommitment` will be different. +- If it is disabled, the circuit will use an empty `aud` private input (as provided by the prover) and skip checking the `aud` field. A valid JWT still needs to be provided and the public inputs hash calculation will still implicitly include the `aud` field via the `IdCommitment` in the `KeylessPublicKey`, but it will be set to the empty value. This means that proofs for `aud`-less accounts will be rejected if the account requires `aud` to be present, as the `IdCommitment` will be different. 2. The prover API will also require an update to allow for indiciating whether the `aud` check is enabled. This will be done by adding a new boolean argument to the `prove` API. From d216427cdaa483c50a75880285fbacc626469466 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 21 Nov 2024 12:22:10 -0500 Subject: [PATCH 04/15] add zk relation --- aips/aip-103.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index f73f9a15..4c1a3ea4 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -1,5 +1,5 @@ --- -aip: 103 +aip: 10X title: Enable interoperability for Federated Keyless Accounts for the same issuer (user-pool/tenant) author: Oliver He (oliver.he@aptoslabs.com) Status: Draft # | Last Call | Accepted | Final | Rejected> @@ -10,7 +10,7 @@ updated (*optional): requires (*optional): https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-103.md --- -# AIP-103 - Enable interoperability for Federated Keyless Accounts for the same issuer (user-pool/tenant) +# AIP-10X - Enable interoperability for Federated Keyless Accounts for the same issuer (user-pool/tenant) ## Summary @@ -31,6 +31,61 @@ Risks - We want such accounts to be limited to Federated Keyless Accounts, as constructing Keyless Accounts without aud checks is unsafe. This can be mitigated by the Aptos SDK disallowing `aud`-less accounts from being used as Keyless Accounts. The prover will also reject proof requests for Keyless providers (as of now Google and Apple). However, in a world where 3rd party provers are permitted, we cannot prevent developers from using `aud`-less accounts as Keyless Accounts, but developers would not have any incentive to construct such accounts for their users (these accounts would be accessable by any other dApp, regardless of trust). - The verification key will need an update, which will invalidate all existing proofs. Additionally the prover will need to start proving with the new proving key right away after the update. The prover has already been updated to support the proving key rotations and the SDK also supports state checks to invalidate old proofs. + +#### The updated keyless ZK relation $$\mathcal{R}$$ + +```math +\mathcal{R}\begin{pmatrix} + \mathsf{pih};\\ + \textbf{w} = [ + \textbf{w}_\mathsf{pub} = ( + \mathsf{epk}, + \mathsf{addr\_idc}, + \mathsf{exp\_date}, + \mathsf{exp\_horizon}, + \mathsf{iss\_val}, + \mathsf{extra\_field}, + \mathsf{header}, + \mathsf{jwk}, + \mathsf{override\_aud\_val} + ),\\ + \textbf{w}_\mathsf{priv} = ( + \mathsf{skip\_aud\_check\_val}, + \mathsf{aud\_key}, + \mathsf{uid\_key}, + \mathsf{uid\_val}, + r, + \sigma_\mathsf{oidc}, + \mathsf{jwt}, + \rho + ) + ] +\end{pmatrix} +``` + +The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part of the verification** from the [leaky mode](#warm-up-leaky-signatures-that-reveal-the-users-and-apps-identity) above: + +1. If using `email`-based IDs, ensure the email has been verified: + - i.e., if $\mathsf{uid\\_key}\stackrel{?}{=}\texttt{"email"}$, assert $\mathsf{jwt}[\texttt{"email\\_verified"}] \stackrel{?}{=} \texttt{"true"}$ +1. Let $\mathsf{uid\\_val}\gets\mathsf{jwt}[\mathsf{uid\\_key}]$ +1. If $\mathsf{idc\\_aud\\_val}$ is set + - *Then:* + + assert that $\mathsf{jwt}[\texttt{"aud"}]$ is an approved recovery service ID in the [`aud` override list](#aud-override-list), stored on chain + + let $\mathsf{aud\\_val}\gets \mathsf{idc\\_aud\\_val}$ + - *Else:* let $\mathsf{aud\\_val}\gets\mathsf{jwt}[\texttt{"aud"}]$ +1. Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$, using the pepper $r$ from the signature +1. Verify that the PK matches the authentication key on-chain: + - Assert $\mathsf{auth\\_key} \stackrel{?}{=} H(\mathsf{iss\\_val}, \mathsf{addr\\_idc})$ +1. Check the EPK is committed in the JWT’s `nonce` field: + - Assert $\mathsf{jwt}[\texttt{"nonce"}] \stackrel{?}{=} H’(\mathsf{epk},\mathsf{exp\\_date};\rho)$ +1. Check the EPK expiration date is not too far off into the future (we detail this below): + - Assert $\mathsf{exp\\_date} < \mathsf{jwt}[\texttt{"iat"}] + \mathsf{max\\_exp\\_horizon}$, where $\mathsf{max\\_exp\\_horizon}$ is an on-chain parameter (see [here](#move-module)) + - (We do not assert the expiration date is in the future (i.e., assert $\mathsf{exp\\_date} > \mathsf{jwt}[\texttt{"iat"}]$). Instead, we assume that the JWT’s issued-at timestamp (`iat`) field is correct and therefore close to the current block time. So if an application mis-sets $\mathsf{exp\\_date} < \mathsf{jwt}[\texttt{"iat"}]$, then the EPK will be expired from the perspective of the blockchain.) +1. Check the EPK is not expired: + - Assert $\texttt{current\\_block\\_time()} < \mathsf{exp\\_date}$ +1. Verify the ephemeral signature $\sigma_\mathsf{eph}$ under $\mathsf{epk}$ over the transaction $\mathsf{txn}$ +1. Fetch the correct PK of the OIDC provider, denoted by $\mathsf{jwk}$, which is identified via the `kid` field in the JWT $\mathsf{header}$. +1. Verify the OIDC signature $\sigma_\mathsf{oidc}$ under $\mathsf{jwk}$ over the JWT $\mathsf{header}$ and payload $\mathsf{jwt}$. ## Alternative solutions The alternative is to add an additional keyless public key type where the formula to compute the IdCommitment does not contain the `aud` at all. From 47563ca1617df4d3455de6f17755bd6cb5d22b91 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 15:56:40 -0500 Subject: [PATCH 05/15] add relation update --- aips/aip-103.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 4c1a3ea4..62969b93 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -50,7 +50,7 @@ Risks \mathsf{override\_aud\_val} ),\\ \textbf{w}_\mathsf{priv} = ( - \mathsf{skip\_aud\_check\_val}, + \mathsf{\textcolor{red}{skip\_aud\_check\_val}}, \mathsf{aud\_key}, \mathsf{uid\_key}, \mathsf{uid\_val}, @@ -65,27 +65,27 @@ Risks The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part of the verification** from the [leaky mode](#warm-up-leaky-signatures-that-reveal-the-users-and-apps-identity) above: -1. If using `email`-based IDs, ensure the email has been verified: - - i.e., if $\mathsf{uid\\_key}\stackrel{?}{=}\texttt{"email"}$, assert $\mathsf{jwt}[\texttt{"email\\_verified"}] \stackrel{?}{=} \texttt{"true"}$ -1. Let $\mathsf{uid\\_val}\gets\mathsf{jwt}[\mathsf{uid\\_key}]$ -1. If $\mathsf{idc\\_aud\\_val}$ is set - - *Then:* - + assert that $\mathsf{jwt}[\texttt{"aud"}]$ is an approved recovery service ID in the [`aud` override list](#aud-override-list), stored on chain - + let $\mathsf{aud\\_val}\gets \mathsf{idc\\_aud\\_val}$ - - *Else:* let $\mathsf{aud\\_val}\gets\mathsf{jwt}[\texttt{"aud"}]$ -1. Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$, using the pepper $r$ from the signature -1. Verify that the PK matches the authentication key on-chain: - - Assert $\mathsf{auth\\_key} \stackrel{?}{=} H(\mathsf{iss\\_val}, \mathsf{addr\\_idc})$ -1. Check the EPK is committed in the JWT’s `nonce` field: +1. Verify that the public inputs hash $\mathsf{pih}$ is correctly derived by hashing the inputs in $\textbf{w}\_\mathsf{pub}$ with $H\_\mathsf{zk}$ (as explained above). +2. Check the OIDC provider ID in the JWT: + - Assert $\mathsf{iss\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"iss"}]$ +3. If using `email`-based IDs, ensure the email has been verified: + - If $\mathsf{uid\\_key}\stackrel{?}{=}\texttt{"email"}$, assert $\mathsf{jwt}[\texttt{"email\\_verified"}] \stackrel{?}{=} \texttt{"true"}$ +4. Check the user’s ID in the JWT: + - Assert $\mathsf{uid\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{uid\\_key}]$ +5. Check the address IDC uses the correct values: + - Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$ +6. If $\mathsf{\textcolor{red}{skip\_aud\_check\_val}}$ is set + - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. + - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ +7. Check the EPK is committed in the JWT’s `nonce` field: - Assert $\mathsf{jwt}[\texttt{"nonce"}] \stackrel{?}{=} H’(\mathsf{epk},\mathsf{exp\\_date};\rho)$ -1. Check the EPK expiration date is not too far off into the future (we detail this below): - - Assert $\mathsf{exp\\_date} < \mathsf{jwt}[\texttt{"iat"}] + \mathsf{max\\_exp\\_horizon}$, where $\mathsf{max\\_exp\\_horizon}$ is an on-chain parameter (see [here](#move-module)) - - (We do not assert the expiration date is in the future (i.e., assert $\mathsf{exp\\_date} > \mathsf{jwt}[\texttt{"iat"}]$). Instead, we assume that the JWT’s issued-at timestamp (`iat`) field is correct and therefore close to the current block time. So if an application mis-sets $\mathsf{exp\\_date} < \mathsf{jwt}[\texttt{"iat"}]$, then the EPK will be expired from the perspective of the blockchain.) -1. Check the EPK is not expired: - - Assert $\texttt{current\\_block\\_time()} < \mathsf{exp\\_date}$ -1. Verify the ephemeral signature $\sigma_\mathsf{eph}$ under $\mathsf{epk}$ over the transaction $\mathsf{txn}$ -1. Fetch the correct PK of the OIDC provider, denoted by $\mathsf{jwk}$, which is identified via the `kid` field in the JWT $\mathsf{header}$. -1. Verify the OIDC signature $\sigma_\mathsf{oidc}$ under $\mathsf{jwk}$ over the JWT $\mathsf{header}$ and payload $\mathsf{jwt}$. +8. Check the EPK expiration date is not too far off into the future: + - Assert $\mathsf{exp\\_date} < \mathsf{jwt}[\texttt{"iat"}] + \mathsf{exp\\_horizon}$ +9. Parse $\mathsf{extra\\_field}$ as $\mathsf{extra\\_field\\_key}$ and $\mathsf{extra\\_field\\_val}$ and assert $\mathsf{extra\\_field\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{extra\\_field\\_key}]$ +10. Verify the OIDC signature $\sigma_\mathsf{oidc}$ under $\mathsf{jwk}$ over the JWT $\mathsf{header}$ and payload $\mathsf{jwt}$. + ## Alternative solutions The alternative is to add an additional keyless public key type where the formula to compute the IdCommitment does not contain the `aud` at all. From fcccf7ccb0368cf93cf4b98c357220cad1528a45 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:02:12 -0500 Subject: [PATCH 06/15] add double slashes --- aips/aip-103.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 62969b93..100f58bd 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -74,10 +74,10 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - Assert $\mathsf{uid\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{uid\\_key}]$ 5. Check the address IDC uses the correct values: - Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$ -6. If $\mathsf{\textcolor{red}{skip\_aud\_check\_val}}$ is set - - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. - - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) - + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ +6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set + - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. + - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ 7. Check the EPK is committed in the JWT’s `nonce` field: - Assert $\mathsf{jwt}[\texttt{"nonce"}] \stackrel{?}{=} H’(\mathsf{epk},\mathsf{exp\\_date};\rho)$ From ea90389ac5a03205521d19ec40a5786cf380e355 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:04:43 -0500 Subject: [PATCH 07/15] add red color --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 100f58bd..223df779 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -74,7 +74,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - Assert $\mathsf{uid\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{uid\\_key}]$ 5. Check the address IDC uses the correct values: - Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$ -6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set +6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ From ee9affe114085a5bca53273ccf68ca2da93817ef Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:14:45 -0500 Subject: [PATCH 08/15] add diff --- aips/aip-103.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 223df779..40297d42 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -74,11 +74,16 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - Assert $\mathsf{uid\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{uid\\_key}]$ 5. Check the address IDC uses the correct values: - Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$ -6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set +6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set to true - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + > *Old version:* + > + > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + > + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + > + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ 7. Check the EPK is committed in the JWT’s `nonce` field: - Assert $\mathsf{jwt}[\texttt{"nonce"}] \stackrel{?}{=} H’(\mathsf{epk},\mathsf{exp\\_date};\rho)$ 8. Check the EPK expiration date is not too far off into the future: From 9a810e5ff7637973ddd646d0d0253682229997eb Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:18:35 -0500 Subject: [PATCH 09/15] update --- aips/aip-103.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 40297d42..f168e7b1 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -74,11 +74,11 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - Assert $\mathsf{uid\\_val}\stackrel{?}{=}\mathsf{jwt}[\mathsf{uid\\_key}]$ 5. Check the address IDC uses the correct values: - Assert $\mathsf{addr\\_idc} \stackrel{?}{=} H'(\mathsf{uid\\_key}, \mathsf{uid\\_val}, \mathsf{aud\\_val}; r)$ -6. If $\mathsf{\textcolor{red}{skip\\_aud\\_check\\_val}}$ is set to true - - *Then:* assert $\mathsf{aud\\_val}$ is the empty string. - - *Else:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) +6. If we are doing `aud` checks (i.e., $\mathsf{skip\\_aud\\_check\\_val} = \bot$) + - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + - *Else:* assert $\mathsf{aud\\_val}$ is the empty string. > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From f8a461fc878a7afde3cd4e0c4f9832f2d180ec4d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:21:42 -0500 Subject: [PATCH 10/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index f168e7b1..45cb6a60 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}$ is the empty string. + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{""} $ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From 28867a16a34697f7da4ce5ed8c0b6c79a8507825 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:22:52 -0500 Subject: [PATCH 11/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 45cb6a60..956a9d34 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{""} $ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{""}$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From 851459d1df6e20cbfb9051b5a84922ebfb9728f4 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:24:15 -0500 Subject: [PATCH 12/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 956a9d34..d8db33d6 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{""}$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From db1f3318f0c0179a3e4b31674fccf2607aca9675 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:24:49 -0500 Subject: [PATCH 13/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index d8db33d6..557d6180 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}[\texttt{"aud"}]$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From 46befa7d40733d0826ad9df272efea798cbd99df Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:25:20 -0500 Subject: [PATCH 14/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index 557d6180..fa32a8d9 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}[\texttt{"aud"}]$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{"aud"}$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) From 69ac01a4d050d4723cf56572af655160864d4920 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 25 Nov 2024 16:25:46 -0500 Subject: [PATCH 15/15] update --- aips/aip-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aips/aip-103.md b/aips/aip-103.md index fa32a8d9..956a9d34 100644 --- a/aips/aip-103.md +++ b/aips/aip-103.md @@ -78,7 +78,7 @@ The **ZK relation $\mathcal{R}$** simply **performs the privacy-sensitive part o - *Then:* Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$) + *Then:* check the managing application’s ID in the JWT: assert $\mathsf{aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ + *Else:* check that the recovery service’s ID is in the JWT: assert $\mathsf{override\\_aud\\_val}\stackrel{?}{=}\mathsf{jwt}[\texttt{"aud"}]$ - - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{"aud"}$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). + - *Else:* assert $\mathsf{aud\\_val}\stackrel{?}{=}\texttt{""}$ (i.e. $\mathsf{aud\\_val}$ should equal the empty string). > *Old version:* > > Are we in normal mode (i.e., we are not in recovery mode $\Leftrightarrow \mathsf{override\\_aud\\_val} = \bot$)