-
Notifications
You must be signed in to change notification settings - Fork 68
Conversation
…ownership Also don’t allow recoveryKey to overwrite existing owners
Fails due to various timestamp related issues
Added tests for migration. Would love some feedback on them :~)
This stops the following attack: Assume there is a single evil owner and any number of good owners. 1. EO calls changeRecovery and changes the recovery to 0. 2. EO then calls forwardTo, and sends data through the proxy to the registerIdentity function in the IdentityManager. 3. In this forward, the EO provides a new ownerKey and a recoveryKey of 0 to the registerIdentity function. Thus, the conditional in the first line is false, and this does not throw. 4. The new owner is then added immediately with full power. 5. Thus, the evilOwner could effectively add a ton of new evil owners and overpower the good identity.
What is the reason for having a separate MetaTx contract? Wouldn't it make sense to put the metaTx verification directly into the MetaIdentityManager? |
@oed This is originally what @christianlundkvist did here: https://github.com/uport-project/uport-identity/blob/feature/identity-manager-metatx/contracts/IdentityManager.sol That specific approach led to a lot of duplicated code, but I think you are right. Moving these functions into the MetaIdenitityManager itself seems like a good idea. |
It's worth noting that a benefit of separating this into a separate contract is that it becomes a "singleton" meta-tx relay. All contracts that conform to the changes necessary for the relay (see here in the section "Changes to Existing Contracts:") are able to interact with it without having to add it to their code. This approach is likely very similar to an abstract contract, as you mentioned. |
contracts/MetaIdentityManager.sol
Outdated
/// @param owner Key who can use this contract to control proxy. Given full power | ||
/// @param recoveryKey Key of recovery network or address from seed to recovery proxy | ||
/// Gas cost of ~300,000 | ||
function CreateIdentity(address owner, address recoveryKey) validRecovery(recoveryKey) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method should start with a small caps letter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oed will update this now.
@oed These are good points, thanks. I'll work on doing this now. Any thoughts on what version of solc to go to? :) |
@naterush The version supported by the latest truffle might be a good idea. Make sure to specify the truffle version without |
8329461
to
4a95c63
Compare
These changes look good to me, I.e. name change, updated solc and dependencies. 👍 |
contracts/TxRelay.sol
Outdated
* @param sigV, sigR, sigS ECDSA signature on some data to be forwarded | ||
* @param data The bytes necessary to call the function in the destination contract. | ||
Note, the first encoded argument in data must be address of the signer | ||
* @param claimedSender Address of the user who is having tx forwarded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be updated since it doesn't seem to be a direct Param?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aldigjo good catch. Will update now.
//Checks that address a is the first input in msg.data. | ||
//Has very minimal gas overhead. | ||
function checkMessageData(address a) constant internal returns (bool t) { | ||
if (msg.data.length < 36) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this check really needed?
- Won't function calls fail if they don't match function signature?
- Won't the
eq
test return false (or throw?) if msg.data.lenth < 36?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought so also, but I had a test case that was failing b/c of this, somehow. Mabe should try to replicate, but I guess this does not really hurt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, all tests work for me without that line. The only reason I ask is because solidity-coverage says that that line isn't covered, and I can't figure out a way to test it. But I guess it's fine to leave it there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@christianlundkvist nope, let's merge :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oed @christianlundkvist requires one more review, but it is probably good to get this out, so we can start testing.
It might be a good idea to add functions for |
@oed happy to add when free on Thursday/Friday. Otherwise, if you want to merge sooner, feel free to add :~) |
@oed @naterush I think it might also be good to have a mapping/function that takes a recovery key and returns the corresponding identity. Also, the way we're doing actual recovery right now might open up an attack: If I create a new identity with someone elses recoveryKey (that I don't control), then you might be able to block the recovery from that person. |
contracts/IdentityManager.sol
Outdated
@@ -208,4 +208,12 @@ contract IdentityManager { | |||
t := eq(a, and(mask, calldataload(4))) | |||
} | |||
} | |||
|
|||
function isOwner(address identity, address user) constant returns (bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User might be a little misleading langauge @oed. Maybe key (as below) would be better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, maybe change to owner
and recoveryKey
in the isRecovery
function. Then it is consistant with everywhere else.
@christianlundkvist Currently, the mapping is from identity => recoveryKey. This helper function would add an extra mapping (extra cost and thing to update, not sure it is worth it). Let me know what you think. Also, not sure I follow the attack you describe. As the mapping is from identity => recovery key, couldn't multiple identities have the same recovery with no issue? |
3de6310
to
0f15d2c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really good. The meta tx code is pretty clear and isolated. So all we need is a separate MetaTxIdentityManager contract now and we should be good to go.
bytes32 h = sha3(this, nonce[claimedSender], destination, data, msg.sender); | ||
address addressFromSig = ecrecover(h, sigV, sigR, sigS); | ||
|
||
nonce[claimedSender]++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@naterush I think it does make sense to move it below just for clarity.
if (b.length < 36) return address(0); | ||
assembly { | ||
let mask := 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | ||
a := and(mask, mload(add(b, 36))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
import "./Proxy.sol"; | ||
|
||
|
||
contract IdentityManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@naterush @oed As I mentioned we need a new contract here. This may actually be a good candidate for inheritance as with the design here the only thing different is the constructor, onlyAuthorized
and checkMessageData
. That would also ensure that changes to the normal IdentityManager would get reflected here automatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can rework this over the weekend. For a name, I think MetaIdentityManager works well.
Also, you mean just define a "ManagerInterface," right? If we do inheritance, I'm not sure we can just add modifiers on to functions (aka, would have to redefine functions anyway).
I do think it would make sense to make sure they share the same interface, though. Let me know what you think @pelle
@pelle thanks. Will update this weekend. For the "I think it does make sense to move it below just for clarity," which line are you referring to? |
contracts/TxRelay.sol
Outdated
//Validity Checks (if these throw this time, they will always throw) | ||
if (claimedSender != addressFromSig) throw; | ||
if (!checkAddress(data, addressFromSig)) throw; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@naterush move line 41 down here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again just for clarity. I know the functionality is the same.
This contains the first attempt at a singleton meta-tx relay contract. An overview, the design decisions, attacks, and thoughts about this can be found on this document: https://consensys.quip.com/CoClAjSTyBZI
Tests are very incomplete -- as of now, just test to make sure it works but not very thorough. Will be adding more in the coming days.
Would love some basic feedback on what exists so far.