Skip to content

Commit 90ca7b4

Browse files
authored
Update isValidSignature replay protection (#620)
* Don't double hash in smart wallet isValidSignature replay protection * Update _originalMessageHash -> _hash * EIP712 typed data signature for isValidSignature
1 parent dbe8914 commit 90ca7b4

File tree

3 files changed

+31
-19
lines changed

3 files changed

+31
-19
lines changed

contracts/prebuilts/account/non-upgradeable/Account.sol

+15-9
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,18 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115
6262
super.supportsInterface(interfaceId);
6363
}
6464

65-
/// @notice See EIP-1271
65+
/**
66+
* @notice See EIP-1271
67+
*
68+
* @param _hash The original message hash of the data to sign (before mixing this contract's domain separator)
69+
* @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`)
70+
*/
6671
function isValidSignature(
67-
bytes32 _message,
72+
bytes32 _hash,
6873
bytes memory _signature
6974
) public view virtual override returns (bytes4 magicValue) {
70-
bytes32 messageHash = getMessageHash(abi.encode(_message));
71-
address signer = messageHash.recover(_signature);
75+
bytes32 targetDigest = getMessageHash(_hash);
76+
address signer = targetDigest.recover(_signature);
7277

7378
if (isAdmin(signer)) {
7479
return MAGICVALUE;
@@ -89,12 +94,13 @@ contract Account is AccountCore, ContractMetadata, ERC1271, ERC721Holder, ERC115
8994

9095
/**
9196
* @notice Returns the hash of message that should be signed for EIP1271 verification.
92-
* @param message Message to be hashed i.e. `keccak256(abi.encode(data))`
93-
* @return Hashed message
97+
* @param _hash The message hash to sign for the EIP-1271 origin verifying contract.
98+
* @return messageHash The digest to sign for EIP-1271 verification.
9499
*/
95-
function getMessageHash(bytes memory message) public view returns (bytes32) {
96-
bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message)));
97-
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash));
100+
function getMessageHash(bytes32 _hash) public view returns (bytes32) {
101+
bytes32 messageHash = keccak256(abi.encode(_hash));
102+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash));
103+
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
98104
}
99105

100106
/*///////////////////////////////////////////////////////////////

contracts/prebuilts/account/utils/AccountExtension.sol

+15-9
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,18 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7
6464
super.supportsInterface(interfaceId);
6565
}
6666

67-
/// @notice See EIP-1271
67+
/**
68+
* @notice See EIP-1271
69+
*
70+
* @param _hash The original message hash of the data to sign (before mixing this contract's domain separator)
71+
* @param _signature The signature produced on signing the typed data hash (result of `getMessageHash(abi.encode(rawData))`)
72+
*/
6873
function isValidSignature(
69-
bytes32 _message,
74+
bytes32 _hash,
7075
bytes memory _signature
7176
) public view virtual override returns (bytes4 magicValue) {
72-
bytes32 messageHash = getMessageHash(abi.encode(_message));
73-
address signer = messageHash.recover(_signature);
77+
bytes32 targetDigest = getMessageHash(_hash);
78+
address signer = targetDigest.recover(_signature);
7479

7580
if (isAdmin(signer)) {
7681
return MAGICVALUE;
@@ -91,12 +96,13 @@ contract AccountExtension is ContractMetadata, ERC1271, AccountPermissions, ERC7
9196

9297
/**
9398
* @notice Returns the hash of message that should be signed for EIP1271 verification.
94-
* @param message Message to be hashed i.e. `keccak256(abi.encode(data))`
95-
* @return Hashed message
99+
* @param _hash The message hash to sign for the EIP-1271 origin verifying contract.
100+
* @return messageHash The digest to sign for EIP-1271 verification.
96101
*/
97-
function getMessageHash(bytes memory message) public view returns (bytes32) {
98-
bytes32 messageHash = keccak256(abi.encode(MSG_TYPEHASH, keccak256(message)));
99-
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), messageHash));
102+
function getMessageHash(bytes32 _hash) public view returns (bytes32) {
103+
bytes32 messageHash = keccak256(abi.encode(_hash));
104+
bytes32 typedDataHash = keccak256(abi.encode(MSG_TYPEHASH, messageHash));
105+
return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), typedDataHash));
100106
}
101107

102108
/*///////////////////////////////////////////////////////////////

src/test/smart-wallet/AccountVulnPOC.t.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ contract SimpleAccountVulnPOCTest is BaseTest {
279279
// However they can bypass this by using signature verification on number contract instead
280280
vm.prank(accountSigner);
281281
bytes32 digest = keccak256(abi.encode(42));
282-
bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(abi.encode(digest));
282+
bytes32 toSign = SimpleAccount(payable(account)).getMessageHash(digest);
283283
(uint8 v, bytes32 r, bytes32 s) = vm.sign(accountSignerPKey, toSign);
284284
bytes memory signature = abi.encodePacked(r, s, v);
285285

0 commit comments

Comments
 (0)