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

fix signature malleability issue #37

Merged
merged 4 commits into from
Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ Links are stored as mapping from addresses to a link Id. Users can have any numb
## Account Registry Logic Public Functions
### linkIds
Public getter to check if an address is linked to another address. Returns 0 if no link.
Retrieve the account Id associated with an address. Reverts if the address is not associated with an account
#### Interface
```
function linkIds(address _address) public view returns (uint256)
Expand All @@ -122,7 +121,7 @@ if (linkA === linkB && linkA !== 0) {
```

### linkAddresses
Store a link demonstrating ownership of multiple addresses. Each address much sign a message indicating intention to be linked. `currentAddress` may be linked to other addresses. `newAddress` must be unclaimed.
Store a link demonstrating ownership of multiple addresses. Each address must sign a message indicating intention to be linked. `currentAddress` may be linked to other addresses. `newAddress` must be unclaimed.

A user can submit this transaction from their own address or it can be submitted by a third party on their behalf.
#### Interface
Expand Down
32 changes: 13 additions & 19 deletions contracts/AccountRegistryLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ contract AccountRegistryLogic is Initializable, SigningLogic {
* @param _currentAddressSig Signed message from address currently associated with account confirming intention
* @param _newAddress Address to add to account. Cannot currently be linked to another address
* @param _newAddressSig Signed message from new address confirming ownership by the sender
* @param _nonce uuid used when generating sigs to make them one time use
* @param _nonce hex string used when generating sigs to make them one time use
*/
function linkAddresses(
address _currentAddress,
Expand All @@ -42,11 +42,9 @@ contract AccountRegistryLogic is Initializable, SigningLogic {
require(linkIds[_newAddress] == 0);
// Confirm new address is signed by current address and is unused
validateLinkSignature(_currentAddress, _newAddress, _nonce, _currentAddressSig);
burnSignature(_currentAddressSig);

// Confirm current address is signed by new address and is unused
validateLinkSignature(_newAddress, _currentAddress, _nonce, _newAddressSig);
burnSignature(_newAddressSig);

// Get linkId of current address if exists. Otherwise use incremented linkCounter
if (linkIds[_currentAddress] == 0) {
Expand All @@ -61,7 +59,7 @@ contract AccountRegistryLogic is Initializable, SigningLogic {
* @notice Remove an address from a link relationship
* @param _addressToRemove Address to unlink from all other addresses
* @param _unlinkSignature Signed message from address currently associated with account confirming intention to unlink
* @param _nonce uuid used when generating sigs to make them one time use
* @param _nonce hex string used when generating sigs to make them one time use
*/
function unlinkAddress(
address _addressToRemove,
Expand All @@ -70,30 +68,27 @@ contract AccountRegistryLogic is Initializable, SigningLogic {
) public {
// Confirm unlink request is signed by sender and is unused
validateUnlinkSignature(_addressToRemove, _nonce, _unlinkSignature);
burnSignature(_unlinkSignature);
linkIds[_addressToRemove] = 0;

emit AddressUnlinked(_addressToRemove);
}

/**
* @notice Verify link signature is valid and unused V
* @param _addressA Address signing intention to link
* @param _addressB Address being linked
* @param _currentAddress Address signing intention to link
* @param _addressToAdd Address being linked
* @param _nonce Unique nonce for this request
* @param _linkSignature Signature of address a
*/
function validateLinkSignature(
address _addressA,
address _addressB,
address _currentAddress,
address _addressToAdd,
bytes32 _nonce,
bytes _linkSignature
) internal view {
require(_addressA == recoverSigner(
generateAddAddressSchemaHash(
_addressB,
_nonce
), _linkSignature));
bytes32 _signatureDigest = generateAddAddressSchemaHash(_addressToAdd, _nonce);
require(_currentAddress == recoverSigner(_signatureDigest, _linkSignature));
burnSignatureDigest(_signatureDigest, _currentAddress);
}

/**
Expand All @@ -111,11 +106,10 @@ contract AccountRegistryLogic is Initializable, SigningLogic {
// require that address to remove is currently linked to senderAddress
require(linkIds[_addressToRemove] != 0, "Address does not have active link");

require(_addressToRemove == recoverSigner(
generateRemoveAddressSchemaHash(
_addressToRemove,
_nonce
), _unlinkSignature));
bytes32 _signatureDigest = generateRemoveAddressSchemaHash(_addressToRemove, _nonce);

require(_addressToRemove == recoverSigner(_signatureDigest, _unlinkSignature));
burnSignatureDigest(_signatureDigest, _addressToRemove);
}

/**
Expand Down
50 changes: 17 additions & 33 deletions contracts/AttestationLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ contract AttestationLogic is Initializable, SigningLogic{
) public {
// Confirm attester address matches recovered address from signature
validateAttestForSig(_subject, _attester, _requester, _reward, _dataHash, _requestNonce, _delegationSig);
burnSignature(_delegationSig);
attestForUser(
_subject,
_attester,
Expand Down Expand Up @@ -134,7 +133,6 @@ contract AttestationLogic is Initializable, SigningLogic{
_requestNonce,
_subjectSig
);
burnSignature(_subjectSig);

emit TraitAttested(
_subject,
Expand Down Expand Up @@ -196,7 +194,6 @@ contract AttestationLogic is Initializable, SigningLogic{
_requestNonce,
_delegationSig
);
burnSignature(_delegationSig);
contestForUser(
_attester,
_requester,
Expand Down Expand Up @@ -242,11 +239,9 @@ contract AttestationLogic is Initializable, SigningLogic{
bytes32 _requestNonce,
bytes _subjectSig
) internal view {
require(_subject == recoverSigner(
generateRequestAttestationSchemaHash(
_dataHash,
_requestNonce
), _subjectSig));
bytes32 _signatureDigest = generateRequestAttestationSchemaHash(_dataHash, _requestNonce);
require(_subject == recoverSigner(_signatureDigest, _subjectSig));
burnSignatureDigest(_signatureDigest, _subject);
}

/**
Expand All @@ -268,15 +263,9 @@ contract AttestationLogic is Initializable, SigningLogic{
bytes32 _requestNonce,
bytes _delegationSig
) internal view {
require(_attester == recoverSigner(
generateAttestForDelegationSchemaHash(
_subject,
_requester,
_reward,
_dataHash,
_requestNonce
),
_delegationSig), 'Invalid AttestFor Signature');
bytes32 _delegationDigest = generateAttestForDelegationSchemaHash(_subject, _requester, _reward, _dataHash, _requestNonce);
require(_attester == recoverSigner(_delegationDigest, _delegationSig), 'Invalid AttestFor Signature');
burnSignatureDigest(_delegationDigest, _attester);
}

/**
Expand All @@ -294,13 +283,9 @@ contract AttestationLogic is Initializable, SigningLogic{
bytes32 _requestNonce,
bytes _delegationSig
) internal view {
require(_attester == recoverSigner(
generateContestForDelegationSchemaHash(
_requester,
_reward,
_requestNonce
),
_delegationSig), 'Invalid ContestFor Signature');
bytes32 _delegationDigest = generateContestForDelegationSchemaHash(_requester, _reward, _requestNonce);
require(_attester == recoverSigner(_delegationDigest, _delegationSig), 'Invalid ContestFor Signature');
burnSignatureDigest(_delegationDigest, _attester);
}

/**
Expand Down Expand Up @@ -342,12 +327,12 @@ contract AttestationLogic is Initializable, SigningLogic{
* @param _link bytes string embedded in dataHash to link revocation
*/
function revokeAttestationFor(
bytes32 _link,
address _sender,
bytes32 _link,
bytes32 _nonce,
bytes _delegationSig
) public {
validateRevokeForSig(_link, _sender, _delegationSig);
burnSignature(_delegationSig);
validateRevokeForSig(_sender, _link, _nonce, _delegationSig);
revokeAttestationForUser(_link, _sender);
}

Expand All @@ -358,15 +343,14 @@ contract AttestationLogic is Initializable, SigningLogic{
* @param _delegationSig signature authorizing revocation on behalf of revoker
*/
function validateRevokeForSig(
bytes32 _link,
address _sender,
bytes32 _link,
bytes32 _nonce,
bytes _delegationSig
) internal view {
require(_sender == recoverSigner(
generateRevokeAttestationForDelegationSchemaHash(
_link
),
_delegationSig), 'Invalid RevokeFor Signature');
bytes32 _delegationDigest = generateRevokeAttestationForDelegationSchemaHash(_link, _nonce);
require(_sender == recoverSigner(_delegationDigest, _delegationSig), 'Invalid RevokeFor Signature');
burnSignatureDigest(_delegationDigest, _sender);
}

/**
Expand Down
22 changes: 13 additions & 9 deletions contracts/Poll.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,21 @@ contract Poll is DependentOnIPFS, SigningLogic {
}

function voteFor(uint16 _choice, address _voter, bytes32 _nonce, bytes _delegationSig) external {
require(_voter == recoverSigner(
generateVoteForDelegationSchemaHash(
_choice,
_voter,
_nonce,
this),
_delegationSig),
validateVoteForSig(_choice, _voter, _nonce, _delegationSig);
voteForUser(_choice, _voter);
}

function validateVoteForSig(
uint16 _choice,
address _voter,
bytes32 _nonce,
bytes _delegationSig
) internal view {
bytes32 _signatureDigest = generateVoteForDelegationSchemaHash(_choice, _voter, _nonce, this);
require(_voter == recoverSigner(_signatureDigest, _delegationSig),
"Invalid signer"
);
burnSignature(_delegationSig);
voteForUser(_choice, _voter);
burnSignatureDigest(_signatureDigest, _voter);
}

/**
Expand Down
20 changes: 12 additions & 8 deletions contracts/SigningLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ contract SigningLogic {
// have been used so they can't be replayed
mapping (bytes32 => bool) public usedSignatures;

function burnSignature(bytes _signature) internal {
bytes32 _signatureHash = keccak256(abi.encodePacked(_signature));
require(!usedSignatures[_signatureHash], "Signature not unique");
usedSignatures[_signatureHash] = true;
function burnSignatureDigest(bytes32 _signatureDigest, address _sender) internal {
bytes32 _txDataHash = keccak256(abi.encode(_signatureDigest, _sender));
require(!usedSignatures[_txDataHash], "Signature not unique");
usedSignatures[_txDataHash] = true;
}

bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
Expand Down Expand Up @@ -52,7 +52,7 @@ contract SigningLogic {
);

bytes32 constant REVOKE_ATTESTATION_FOR_TYPEHASH = keccak256(
"RevokeAttestationFor(bytes32 link)"
"RevokeAttestationFor(bytes32 link,bytes32 nonce)"
);

bytes32 constant VOTE_FOR_TYPEHASH = keccak256(
Expand Down Expand Up @@ -183,12 +183,14 @@ contract SigningLogic {

struct RevokeAttestationFor {
bytes32 link;
bytes32 nonce;
}

function hash(RevokeAttestationFor request) internal pure returns (bytes32) {
return keccak256(abi.encode(
REVOKE_ATTESTATION_FOR_TYPEHASH,
request.link
request.link,
request.nonce
));
}

Expand Down Expand Up @@ -348,14 +350,16 @@ contract SigningLogic {
}

function generateRevokeAttestationForDelegationSchemaHash(
bytes32 _link
bytes32 _link,
bytes32 _nonce
) internal view returns (bytes32) {
return keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
hash(RevokeAttestationFor(
_link
_link,
_nonce
))
)
);
Expand Down
35 changes: 9 additions & 26 deletions contracts/TokenEscrowMarketplace.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ contract TokenEscrowMarketplace is SigningLogic {
_nonce,
_delegationSig
);
burnSignature(_delegationSig);
moveTokensToEscrowLockupForUser(_sender, _amount);
}

Expand All @@ -90,13 +89,9 @@ contract TokenEscrowMarketplace is SigningLogic {
bytes _delegationSig

) internal view {
require(_sender == recoverSigner(
generateLockupTokensDelegationSchemaHash(
_sender,
_amount,
_nonce
),
_delegationSig), 'Invalid LockupTokens Signature');
bytes32 _signatureDigest = generateLockupTokensDelegationSchemaHash(_sender, _amount, _nonce);
require(_sender == recoverSigner(_signatureDigest, _delegationSig), 'Invalid LockupTokens Signature');
burnSignatureDigest(_signatureDigest, _sender);
}

/**
Expand Down Expand Up @@ -143,7 +138,6 @@ contract TokenEscrowMarketplace is SigningLogic {
_nonce,
_delegationSig
);
burnSignature(_delegationSig);
releaseTokensFromEscrowForUser(_sender, _amount);
}

Expand All @@ -161,13 +155,9 @@ contract TokenEscrowMarketplace is SigningLogic {
bytes _delegationSig

) internal view {
require(_sender == recoverSigner(
generateReleaseTokensDelegationSchemaHash(
_sender,
_amount,
_nonce
),
_delegationSig), 'Invalid ReleaseTokens Signature');
bytes32 _signatureDigest = generateReleaseTokensDelegationSchemaHash(_sender, _amount, _nonce);
require(_sender == recoverSigner(_signatureDigest, _delegationSig), 'Invalid ReleaseTokens Signature');
burnSignatureDigest(_signatureDigest, _sender);
}

/**
Expand Down Expand Up @@ -229,8 +219,6 @@ contract TokenEscrowMarketplace is SigningLogic {
_nonce,
_paymentSig
);
burnSignature(_paymentSig);

payTokensFromEscrow(_payer, _receiver, _amount);
emit TokenMarketplaceEscrowPayment(_payer, _receiver, _amount);
}
Expand All @@ -251,14 +239,9 @@ contract TokenEscrowMarketplace is SigningLogic {
bytes _paymentSig

) internal view {
require(_payer == recoverSigner(
generatePayTokensSchemaHash(
_payer,
_receiver,
_amount,
_nonce
),
_paymentSig), 'Invalid Payment Signature');
bytes32 _signatureDigest = generatePayTokensSchemaHash(_payer, _receiver, _amount, _nonce);
require(_payer == recoverSigner(_signatureDigest, _paymentSig), 'Invalid Payment Signature');
burnSignatureDigest(_signatureDigest, _payer);
}

/**
Expand Down
Loading