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

Webauthn verifier #25

Merged
merged 6 commits into from
Oct 19, 2023
Merged

Webauthn verifier #25

merged 6 commits into from
Oct 19, 2023

Conversation

nalinbhardwaj
Copy link
Member

@nalinbhardwaj nalinbhardwaj commented Oct 17, 2023

  • Base64URL
  • Webauthn verifier
  • Base64URL tests
  • Webauthn tests

Currently manually tested using the input generated in scratchpad daimo-eth/daimo#330

@socket-security
Copy link

New dependencies detected. Learn more about Socket for GitHub ↗︎

Packages Version New capabilities Transitives Size Publisher
@scure/base 1.1.3 None +0 77.8 kB paulmillr

Copy link
Member

@dcposch dcposch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGreatTM

src/WebAuthn.sol Show resolved Hide resolved
src/WebAuthn.sol Outdated
}

// Check the UV bit
if (requireUserVerification && (flags & 0x04) != 0x04) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we are including that check after all?

Copy link
Member Author

@nalinbhardwaj nalinbhardwaj Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in Daimo usage we should pass this requireUserVerification = false. It should be the passkey authenticator's job to enforce such conditions (and the good ones we use seem to do it properly already), just leaving this here in case other users want it for any reason, as it also means we have feature parity for current users of FCL's Webauthn implementation.

src/WebAuthn.sol Outdated
'"'
);

if (!contains(challenge_property, clientDataJSON, challengeLocation)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super clearly written 🚀

return true;
}

function verifySignature(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add comment. sommething lke

/**
 * Verifies a Webauthn P256 signature. Specifically:
 * - Verifies that authenticatorData (which comes from the authenticator, such as iCloud Keychain) indicates a secure signature. If requireUserVerification is set, checks that the authenticator attests that the user was present for signing (such as via FaceID).
 * - Verifies that the client JSON contains the given challenge. Ignores everything else in the client JSON.
 * - Finally, verifies that (r, s) constitute a valid signature over both the authenicatorData and client JSON, for public key (x, y).
 */

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a much more detailed commenting in this file. Let me know if it looks good.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10/10

}
}

return string(result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super clean.


library Base64URL {
function encode(bytes memory data) public pure returns (string memory) {
string memory strb64 = Base64.encode(data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alternative approach to consider:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Base64.sol

^ base64 is pretty small. i think we could turn it into Base64URL by:

  • changing two characters in the table
  • removing the lines about adding equals signs
  • computing a correct (no equals padding) length for the result string

...so ours would be a small diff on theirs and actually shorter

wonder if OZ would include it in a future release, would fit imo

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no strong opinion either way, but I slightly prefer this so we're not touching any assembly / hand wrangling of bytes ourselves. Will go with this for now unless you feel strongly.

);

// Write to JSON
const filepath = "./vectors_scure_base64url.jsonl";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

test/utils/Base64URL.t.sol Outdated Show resolved Hide resolved
@nalinbhardwaj
Copy link
Member Author

image

100% coverage

@nalinbhardwaj nalinbhardwaj merged commit 88bbcc7 into master Oct 19, 2023
5 checks passed
bytes memory b64 = bytes(strb64);

// count and ignore all "=" symbols from the end of the string
uint256 equalsCount = 0;
Copy link
Member

@dcposch dcposch Oct 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given that there can be at most 2 equals at the end we could also say

uint256 equalsCount = 0; // Base64 can end with "=" or "=="; Base64URL has no padding.
if (b64[b64.length - 2] == "=")  equalsCount = 2;
else if (b64[b64.length - 1] == "=") equalsCount = 1;

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

Successfully merging this pull request may close these issues.

2 participants