From d171c3d7436c3f8d0ac1cb383309162c244f2a58 Mon Sep 17 00:00:00 2001 From: Maor Zamski Date: Thu, 13 Jun 2019 17:22:59 -0700 Subject: [PATCH 1/8] Add EIP-1654 --- EIPS/eip-1654.md | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 EIPS/eip-1654.md diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md new file mode 100644 index 00000000000000..5e6b2bbafc14df --- /dev/null +++ b/EIPS/eip-1654.md @@ -0,0 +1,123 @@ +--- +eip: 1654 +title: Dapp-wallet authentication process with contract wallets support +author: Maor Zamski (@pazams) +discussions-to: https://github.com/ethereum/EIPs/issues/1654 +status: Draft +type: Meta +created: 2018-12-12 +--- + +## Simple Summary + +An off-chain process for dapps to assert whether an entity has authorized control (informally, "ownership") over a public Ethereum address using `eth_sign`. Supports both external wallets and contract wallets. + +## Definitions +- `contract wallet` A contract [account](https://github.com/ethereum/wiki/wiki/White-Paper#ethereum-accounts) deployed with the intent to be used as the ownership address for on-chain assets (including ether, ERC-20 tokens, and ERC-721 NFTs). It has the ability to transfer ether or dynamically execute actions on other contracts (acting as the owner of assets controlled by those contracts). Common examples of contract wallets are `multisig wallets` (such as the ones provided by [Gnosis](https://github.com/Gnosis/MultiSigWallet) and [Parity](https://github.com/ConsenSys/MultiSigWallet)) and `identity contracts`, as defined in [ERC-725](https://github.com/ethereum/EIPs/issues/725). +- `external wallet` An externally owned [account](https://github.com/ethereum/wiki/wiki/White-Paper#ethereum-accounts), controlled by a private key. Currently, most on-chain assets are owned by such accounts. A common example for an external wallet are the wallets generated by MetaMask. +- `authorized signer` An entity is considered to have authorized control over a wallet if either: + - It produced a signature of which the recovered address matches the wallet address. + - It produced a signature of which the contract at the wallet address responds with the magic value `0x1626ba7e` to the `IsValidSignature` contract call. + +## Abstract + +The authentication process starts with the dapp client component requesting a message signature from the wallet. +The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has authorized control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets and contract wallets that support EIP-1271 with `0x1626ba7e` as a magic return value. + +## Motivation + +Dapps frequently offer a customised off-chain user experience in addition to their smart-contract interface. For example, a dapp may provide a push notification feature to their users, allowing them to stay notified about successful state changes associated with their public addresses. For these type of features, a dapp needs a way to assert that a user has authorized control over the public address associated with their account. + +A common practice dapps use in an authentication process is to only check if a recovered public key matches the requested authentication address. For contract wallets, this check is broken, as there is no corresponding private key to which to generate a signed message, and hence why some dapps are inaccessible for contract wallet users. It is therefore argued that a more broader approach is needed. + +## Specification + +### Dapp + +On the dapp side, the dapp-wallet authentication process MUST follow these steps: +1. Dapp client requests the wallet software to sign a challenge message via [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign). +2. Dapp client sends the signature to the dapp's backend component, along with the wallet address to be authenticated with. The address may be obtained via [`eth_accounts`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts). +3. Dapp backend recovers a public key from the signature. +4. Dapp backend checks if the recovered key has authorized control over the provided wallet address under the assumption it could represent an external wallet OR a contract wallet. For the case of a contract wallet, it MUST call `IsValidSignature` and expect the value `0x1626ba7e` to determine whether the entity who signed the challenge has authorized control over the wallet. +5. The result of the authorized control check is returned as the result of the authentication and the flow is complete. + +A challenge message SHOULD contain a random component. This will reduce the risk of replay attacks. + +A challenge message SHOULD be generated by the dapp backend AND not get sent back as input from the dapp client, but be persisted in the backend for at least the entirety of the authentication process. This will remove the risk of accepting forged challenges. + +The following algorithm MAY be used by dapp backend for authenticating users with personal signed messages: + +``` +FUNCTION IsAuthorizedSigner(challengeString, signature, walletAddress) RETURNS (success) + + SET personalChallengeHash to the hash of: challengeString prepended with `"\x19Ethereum Signed Message:\n" + len(challengeString)` + + SET recoveredKey to the public key recovered from signature and personalChallengeHash + + SET recoveredAddress to the address corresponding with recoveredKey + + // try external wallet + IF walletAddress EQUALS recoveredAddress + RETURN true + END IF + + SET challengeHash to the hash of: challengeString . We send just a regular Keccak256 hash, which then the smart contract hashes ontop to an erc191 hash. + + SET contractResult to the result of calling IsValidSignature(challengeHash, signature) on the contract at walletAddress + + IF contractResult EQUALS 0x1626ba7e + RETURN true + ELSE + RETURN false + END IF + +END FUNCTION +``` + +### Wallet + +#### External wallet +Any software agents managing external wallets are not required to make any changes to continue to work with this process. + +#### Contract wallet + +##### Contract + +The contract MUST implement the [isValidSignature](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md) method as suggested by EIP-1271, yet in this variation: + +```Solidity +function isValidSignature(bytes32 hash, bytes _signature) returns(bytes4 magicValue); +``` + +Before recovering a public key, the `bytes32 hash` parameter MUST get hashed again with [EIP-191](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md), with 0 for "version" and the wallet address for "version specific data". + +The `bytes _signature` parameter MAY contain multiple concatenated signatures in case of a multi-sig wallet. + +The method MUST return `0x1626ba7e` if the public key (or keys) recovered from the signature (or signatures) are as expected according to the wallet's own key management logic. Otherwise the method MUST return `0x00000000`. + +##### User agent + +A user agent intended to work with the contract MUST generate signatures over a EIP-191 hash of a regular Keccak256 hash of the challenge message. + +## Rationale + + +EIP-1271 has done a great work with starting the discussion on a standard signature validation method for contracts. At the time of writing, it is still in draft, with several suggestions for the shape of the interface (e.g see [here](https://github.com/ethereum/EIPs/issues/1271#issuecomment-455356404)). This proposal takes one of the variations mentioned in the discussion, and builds on top of it a process for dapp-wallet authentication. + +## Backwards Compatibility + +- external wallets are backwards compatible with this process. +- contract wallets with EIP-1271 support, are compatible with this process to the extent of supporting the method format suggested here and it's corresponding magic value. + +## Implementation + +Packages implementing the purposed algorithm: +- Javascript: https://github.com/dapperlabs/dappauth.js +- Go: https://github.com/dapperlabs/dappauth + + +## Copyright +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). + +--- +Thanks to @dete @Arachnid @chrisaxiom @igorbarbashin @turbolent @jordanschalm @hwrdtm for feedback and suggestions From 81902179601123fc3b05e0bcb9ff129e7b16e7af Mon Sep 17 00:00:00 2001 From: pazams Date: Mon, 17 Jun 2019 13:47:11 -0700 Subject: [PATCH 2/8] Remove commented instructions --- EIPS/eip-1654.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 5e6b2bbafc14df..3066704a6dbd7c 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -9,7 +9,6 @@ created: 2018-12-12 --- ## Simple Summary - An off-chain process for dapps to assert whether an entity has authorized control (informally, "ownership") over a public Ethereum address using `eth_sign`. Supports both external wallets and contract wallets. ## Definitions @@ -20,12 +19,10 @@ An off-chain process for dapps to assert whether an entity has authorized contro - It produced a signature of which the contract at the wallet address responds with the magic value `0x1626ba7e` to the `IsValidSignature` contract call. ## Abstract - The authentication process starts with the dapp client component requesting a message signature from the wallet. The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has authorized control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets and contract wallets that support EIP-1271 with `0x1626ba7e` as a magic return value. ## Motivation - Dapps frequently offer a customised off-chain user experience in addition to their smart-contract interface. For example, a dapp may provide a push notification feature to their users, allowing them to stay notified about successful state changes associated with their public addresses. For these type of features, a dapp needs a way to assert that a user has authorized control over the public address associated with their account. A common practice dapps use in an authentication process is to only check if a recovered public key matches the requested authentication address. For contract wallets, this check is broken, as there is no corresponding private key to which to generate a signed message, and hence why some dapps are inaccessible for contract wallet users. It is therefore argued that a more broader approach is needed. @@ -100,17 +97,13 @@ The method MUST return `0x1626ba7e` if the public key (or keys) recovered from t A user agent intended to work with the contract MUST generate signatures over a EIP-191 hash of a regular Keccak256 hash of the challenge message. ## Rationale - - EIP-1271 has done a great work with starting the discussion on a standard signature validation method for contracts. At the time of writing, it is still in draft, with several suggestions for the shape of the interface (e.g see [here](https://github.com/ethereum/EIPs/issues/1271#issuecomment-455356404)). This proposal takes one of the variations mentioned in the discussion, and builds on top of it a process for dapp-wallet authentication. ## Backwards Compatibility - - external wallets are backwards compatible with this process. - contract wallets with EIP-1271 support, are compatible with this process to the extent of supporting the method format suggested here and it's corresponding magic value. ## Implementation - Packages implementing the purposed algorithm: - Javascript: https://github.com/dapperlabs/dappauth.js - Go: https://github.com/dapperlabs/dappauth From 2535c41785a9586420fbc8da546865f797464c80 Mon Sep 17 00:00:00 2001 From: pazams Date: Mon, 17 Jun 2019 13:55:41 -0700 Subject: [PATCH 3/8] Adjust title and simple summary to match --- EIPS/eip-1654.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 3066704a6dbd7c..8c9ddbcee07800 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -1,6 +1,6 @@ --- eip: 1654 -title: Dapp-wallet authentication process with contract wallets support +title: Off-chain dapp-wallet authentication process with contract wallets support author: Maor Zamski (@pazams) discussions-to: https://github.com/ethereum/EIPs/issues/1654 status: Draft @@ -9,7 +9,7 @@ created: 2018-12-12 --- ## Simple Summary -An off-chain process for dapps to assert whether an entity has authorized control (informally, "ownership") over a public Ethereum address using `eth_sign`. Supports both external wallets and contract wallets. +An off-chain dapp-wallet authentication process. The process asserts whether an entity has authorized control (informally, "ownership") over a public Ethereum address using `eth_sign`. Supports both external wallets and contract wallets. ## Definitions - `contract wallet` A contract [account](https://github.com/ethereum/wiki/wiki/White-Paper#ethereum-accounts) deployed with the intent to be used as the ownership address for on-chain assets (including ether, ERC-20 tokens, and ERC-721 NFTs). It has the ability to transfer ether or dynamically execute actions on other contracts (acting as the owner of assets controlled by those contracts). Common examples of contract wallets are `multisig wallets` (such as the ones provided by [Gnosis](https://github.com/Gnosis/MultiSigWallet) and [Parity](https://github.com/ConsenSys/MultiSigWallet)) and `identity contracts`, as defined in [ERC-725](https://github.com/ethereum/EIPs/issues/725). From 6d10c2e9ec1100c09cf5dbc6117821fa46f9716b Mon Sep 17 00:00:00 2001 From: pazams Date: Mon, 17 Jun 2019 14:08:29 -0700 Subject: [PATCH 4/8] Clear up relation to 1271 --- EIPS/eip-1654.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 8c9ddbcee07800..90a058cdd414ab 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -16,11 +16,11 @@ An off-chain dapp-wallet authentication process. The process asserts whether an - `external wallet` An externally owned [account](https://github.com/ethereum/wiki/wiki/White-Paper#ethereum-accounts), controlled by a private key. Currently, most on-chain assets are owned by such accounts. A common example for an external wallet are the wallets generated by MetaMask. - `authorized signer` An entity is considered to have authorized control over a wallet if either: - It produced a signature of which the recovered address matches the wallet address. - - It produced a signature of which the contract at the wallet address responds with the magic value `0x1626ba7e` to the `IsValidSignature` contract call. + - It produced a signature of which the contract at the wallet address responds with the magic value `0x1626ba7e` to the `isValidSignature()` contract call. ## Abstract The authentication process starts with the dapp client component requesting a message signature from the wallet. -The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has authorized control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets and contract wallets that support EIP-1271 with `0x1626ba7e` as a magic return value. +The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has authorized control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets, as well with contract wallets that support the `isValidSignature()` method specified in this document. ## Motivation Dapps frequently offer a customised off-chain user experience in addition to their smart-contract interface. For example, a dapp may provide a push notification feature to their users, allowing them to stay notified about successful state changes associated with their public addresses. For these type of features, a dapp needs a way to assert that a user has authorized control over the public address associated with their account. @@ -35,7 +35,7 @@ On the dapp side, the dapp-wallet authentication process MUST follow these steps 1. Dapp client requests the wallet software to sign a challenge message via [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign). 2. Dapp client sends the signature to the dapp's backend component, along with the wallet address to be authenticated with. The address may be obtained via [`eth_accounts`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts). 3. Dapp backend recovers a public key from the signature. -4. Dapp backend checks if the recovered key has authorized control over the provided wallet address under the assumption it could represent an external wallet OR a contract wallet. For the case of a contract wallet, it MUST call `IsValidSignature` and expect the value `0x1626ba7e` to determine whether the entity who signed the challenge has authorized control over the wallet. +4. Dapp backend checks if the recovered key has authorized control over the provided wallet address under the assumption it could represent an external wallet OR a contract wallet. For the case of a contract wallet, it MUST call `isValidSignature()` and expect the value `0x1626ba7e` to determine whether the entity who signed the challenge has authorized control over the wallet. 5. The result of the authorized control check is returned as the result of the authentication and the flow is complete. A challenge message SHOULD contain a random component. This will reduce the risk of replay attacks. @@ -60,7 +60,7 @@ FUNCTION IsAuthorizedSigner(challengeString, signature, walletAddress) RETURNS ( SET challengeHash to the hash of: challengeString . We send just a regular Keccak256 hash, which then the smart contract hashes ontop to an erc191 hash. - SET contractResult to the result of calling IsValidSignature(challengeHash, signature) on the contract at walletAddress + SET contractResult to the result of calling isValidSignature(challengeHash, signature) on the contract at walletAddress IF contractResult EQUALS 0x1626ba7e RETURN true @@ -80,7 +80,7 @@ Any software agents managing external wallets are not required to make any chang ##### Contract -The contract MUST implement the [isValidSignature](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md) method as suggested by EIP-1271, yet in this variation: +The contract MUST implement the following method: ```Solidity function isValidSignature(bytes32 hash, bytes _signature) returns(bytes4 magicValue); @@ -90,18 +90,18 @@ Before recovering a public key, the `bytes32 hash` parameter MUST get hashed aga The `bytes _signature` parameter MAY contain multiple concatenated signatures in case of a multi-sig wallet. -The method MUST return `0x1626ba7e` if the public key (or keys) recovered from the signature (or signatures) are as expected according to the wallet's own key management logic. Otherwise the method MUST return `0x00000000`. +The method MUST return `0x1626ba7e` if the public key (or keys) recovered from the signature (or signatures) is determined to have ownership over the wallet according to the wallet's own key management logic. Otherwise the method MUST return `0x00000000`. ##### User agent A user agent intended to work with the contract MUST generate signatures over a EIP-191 hash of a regular Keccak256 hash of the challenge message. ## Rationale -EIP-1271 has done a great work with starting the discussion on a standard signature validation method for contracts. At the time of writing, it is still in draft, with several suggestions for the shape of the interface (e.g see [here](https://github.com/ethereum/EIPs/issues/1271#issuecomment-455356404)). This proposal takes one of the variations mentioned in the discussion, and builds on top of it a process for dapp-wallet authentication. +EIP-1271 has done a great work with starting the discussion on a standard signature validation method for contracts. At the time of writing, it is still in draft, with several suggestions for the shape of the interface (e.g see [here](https://github.com/ethereum/EIPs/issues/1271#issuecomment-455356404) and [here](https://github.com/ethereum/EIPs/issues/1271#issuecomment-488648761)). This proposal takes one of the variations mentioned in the discussion, and builds on top of it a process for dapp-wallet authentication. ## Backwards Compatibility -- external wallets are backwards compatible with this process. -- contract wallets with EIP-1271 support, are compatible with this process to the extent of supporting the method format suggested here and it's corresponding magic value. +- External wallets are backwards compatible with this process. +- Contract wallets need to support `isValidSignature()` as specified in this document. ## Implementation Packages implementing the purposed algorithm: From 3d6869b45a344a20d451647aa40c8b4b1964b9df Mon Sep 17 00:00:00 2001 From: pazams Date: Wed, 26 Jun 2019 14:10:31 -0700 Subject: [PATCH 5/8] Add more specification for solidity interface --- EIPS/eip-1654.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 90a058cdd414ab..6b77230bba9a68 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -83,15 +83,29 @@ Any software agents managing external wallets are not required to make any chang The contract MUST implement the following method: ```Solidity -function isValidSignature(bytes32 hash, bytes _signature) returns(bytes4 magicValue); +pragma solidity ^0.5.0; + +contract ERC1654 { + + // bytes4(keccak256("isValidSignature(bytes32,bytes)") + bytes4 constant internal MAGICVALUE = 0x1626ba7e; + + /** + * @param hash contains 32 bytes of data to be verified with the signature over this contract's address. + * @param signature byte array associated with hash. MAY contain multiple concatenated signatures in case of a multi-sig wallet. + * + * Before recovering a public key, the `bytes32 hash` parameter MUST get hashed again with [EIP-191](https://eips.ethereum.org/EIPS/eip-191), with 0 for "version" and the wallet address for "version specific data". + * The function MUST return the bytes4 `0x1626ba7e` value if the public key (or keys) recovered from the signature (or signatures) is determined to have ownership over the wallet according to the wallet's own key management logic. Otherwise the function MUST return `0x00000000`. + */ + function isValidSignature( + bytes32 hash, + bytes memory signature) + public + view + returns (bytes4 magicValue); +} ``` -Before recovering a public key, the `bytes32 hash` parameter MUST get hashed again with [EIP-191](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md), with 0 for "version" and the wallet address for "version specific data". - -The `bytes _signature` parameter MAY contain multiple concatenated signatures in case of a multi-sig wallet. - -The method MUST return `0x1626ba7e` if the public key (or keys) recovered from the signature (or signatures) is determined to have ownership over the wallet according to the wallet's own key management logic. Otherwise the method MUST return `0x00000000`. - ##### User agent A user agent intended to work with the contract MUST generate signatures over a EIP-191 hash of a regular Keccak256 hash of the challenge message. From cd583e352b97d107fe3d76fbbebb1a0c01a0498a Mon Sep 17 00:00:00 2001 From: pazams Date: Wed, 26 Jun 2019 14:20:46 -0700 Subject: [PATCH 6/8] Add 191 dependency requirment --- EIPS/eip-1654.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 6b77230bba9a68..db294eb28b203a 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -6,6 +6,7 @@ discussions-to: https://github.com/ethereum/EIPs/issues/1654 status: Draft type: Meta created: 2018-12-12 +requires: 191 --- ## Simple Summary From e78c26bb63997be4ceeee4123ee3be9bcbb8aae4 Mon Sep 17 00:00:00 2001 From: pazams Date: Wed, 26 Jun 2019 14:28:35 -0700 Subject: [PATCH 7/8] Edit authors --- EIPS/eip-1654.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index db294eb28b203a..9ce5fd3d8905e6 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -1,7 +1,7 @@ --- eip: 1654 title: Off-chain dapp-wallet authentication process with contract wallets support -author: Maor Zamski (@pazams) +author: Maor Zamski (@pazams), Chris Scott (@chrisaxiom) discussions-to: https://github.com/ethereum/EIPs/issues/1654 status: Draft type: Meta @@ -128,4 +128,4 @@ Packages implementing the purposed algorithm: Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). --- -Thanks to @dete @Arachnid @chrisaxiom @igorbarbashin @turbolent @jordanschalm @hwrdtm for feedback and suggestions +Thanks to @dete @Arachnid @igorbarbashin @turbolent @jordanschalm @hwrdtm for feedback and suggestions From 93c0f15d632557a5138dfe9e88fbd5449e7ac599 Mon Sep 17 00:00:00 2001 From: pazams Date: Wed, 26 Jun 2019 15:04:27 -0700 Subject: [PATCH 8/8] Edit authors --- EIPS/eip-1654.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-1654.md b/EIPS/eip-1654.md index 9ce5fd3d8905e6..618900bcf3673e 100644 --- a/EIPS/eip-1654.md +++ b/EIPS/eip-1654.md @@ -1,7 +1,7 @@ --- eip: 1654 title: Off-chain dapp-wallet authentication process with contract wallets support -author: Maor Zamski (@pazams), Chris Scott (@chrisaxiom) +author: Maor Zamski (@pazams), Christopher Scott (@chrisaxiom) discussions-to: https://github.com/ethereum/EIPs/issues/1654 status: Draft type: Meta