Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multisigs/Gnosis safe wallets do not work out of the box #63

Closed
UTkzhang opened this issue Jun 11, 2024 · 9 comments
Closed

Multisigs/Gnosis safe wallets do not work out of the box #63

UTkzhang opened this issue Jun 11, 2024 · 9 comments

Comments

@UTkzhang
Copy link

UTkzhang commented Jun 11, 2024

In verify function,

   try:
      address = w3.eth.account.recover_message(message, signature=signature)
  except ValueError:
      address = None
  except eth_utils.exceptions.ValidationError as e:
      raise InvalidSignature from None

This recover_message runs into the ValidationError: "Unexpected recoverable signature length: Expected 65, but got 130 bytes" for a 2 signer signature, and raises Exception with cause None instead of going on to check_contract_wallet_signature.

This should not be the behaviour and causes all multisig signers to not work with SIWE lib out of the box.

Reproduce: try signing a SIWE message with 2 signers multisig like safe wallet and see if verify is able to authenticate it.

Proposed fix:
if sig is not 65, instead of raising, continue to check check_contract_wallet_signature eip1271 directly, because it is either a multisig or the user passed in the wrong string somehow. Only raise if check_contract_wallet_signature fails.

@sbihel
Copy link
Member

sbihel commented Jun 12, 2024

In your call to the verify function, do you supply a provider? Here is an example with a test for contract wallets

def test_eip1271_message(self, test_name, test):

@UTkzhang
Copy link
Author

Yes the provider isn’t the issue - it’s the fact that multi sig contract wallets have non standard signature lengths which aren’t handled corrected at the moment

@UTkzhang
Copy link
Author

UTkzhang commented Jun 13, 2024

In the sample test json, I see the sig is a single signer from a smart contract wallet. Try a multi signer variant (2 signers for example).

The multi sig signature is a concat of all the individual signatures so in the test you can reproduce by doubling the length of the signature.

@sbihel
Copy link
Member

sbihel commented Jun 14, 2024

I'm fairly certain that the error about the signature length is a red herring as it is the reason why the EIP-191 failed, but it doesn't mean EIP-1271 wasn't tried (it's unfortunate, but there's no way of knowing in advance what "kind" of signature it is).

Would you be able to provide an example? You mentioned Safe and it does support EIP-1271, so I'm curious what is the root cause.

@UTkzhang
Copy link
Author

Yea my point is exactly that - the standard recover fails, the eip1271 is implemented correctly, no issues there.

The bug is that due to multi sig wallets returning a signature that is of non standard length, it errors on the recover method and never makes it to the subsequent eip1271 verification.

As highlighted in original issue:
This recover_message runs into the ValidationError: "Unexpected recoverable signature length: Expected 65, but got 130 bytes" for a 2 signer signature, and raises Exception with cause None instead of going on to check_contract_wallet_signature.

So it is the eip191 failing, but it is also confirmed that the eip1271 isn’t tried because it raises on this recover_message line instead of continuing like all other cases.

@UTkzhang
Copy link
Author

try:
      address = w3.eth.account.recover_message(message, signature=signature) # fails due to wrong sig length
  except ValueError:
      address = None
  except eth_utils.exceptions.ValidationError as e:
      raise InvalidSignature from None # raised to upper level and never makes it to the next line for eip1271

@sbihel
Copy link
Member

sbihel commented Jun 17, 2024

I looked a bit more into it and we already have a test for EIP-1271 with a signature that's 66 bytes long https://github.com/spruceid/siwe/blob/4290e1fb3702c97ffee16112492216ad4c4654c1/test/eip1271.json#L8. Would you be able to provide an example because I don't know how to reproduce it right now?

@UTkzhang
Copy link
Author

UTkzhang commented Jun 17, 2024

Make the test signature a 130 byte one and it can be reproduced. Add a test with a eip1271 signature that is 130 bytes long.

like literally double the current signature by copy pasting itself and append to end of the signature - the signature would be expected to fail at the eip1271 level since it’s now a made up one, but it won’t. It will fail before it reaches the check_contract_wallet_signature line. That’s the bug.

@UTkzhang
Copy link
Author

UTkzhang commented Jun 17, 2024

You can get the signature to a real transaction by signing it with more than one signer, any multisig wallet will concat the signatures together, so 2 signers would be 130 bytes, and adding 65 bytes for each signer added

@UTkzhang UTkzhang changed the title Multisigs/Gnosis safe wallets do not worth out of the box Multisigs/Gnosis safe wallets do not work out of the box Jun 28, 2024
@sbihel sbihel closed this as completed in 9741fcf Oct 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants