Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ artifacts-selected
cache_hardhat

lcov.info
settings.json
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "lib/I4337"]
path = lib/I4337
url = https://github.com/leekt/I4337
[submodule "lib/p256-verifier"]
path = lib/p256-verifier
url = https://github.com/daimo-eth/p256-verifier
1 change: 1 addition & 0 deletions lib/p256-verifier
Submodule p256-verifier added at 29475a
82 changes: 82 additions & 0 deletions src/validator/modularPermission/signers/WebAuthnSigner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
pragma solidity ^0.8.0;

import {WebAuthn} from "p256-verifier/WebAuthn.sol";
import {ISigner} from "../ISigner.sol";
import {ValidationData} from "../../../common/Types.sol";
import {SIG_VALIDATION_FAILED} from "../../../common/Constants.sol";

struct WebAuthnValidatorData {
uint256 x;
uint256 y;
}

contract WebAuthnSigner is ISigner {
mapping(address caller => mapping(bytes32 permissionId => mapping(address kernel => WebAuthnValidatorData))) public
webAuthnValidatorStorage;

function registerSigner(address kernel, bytes32 permissionId, bytes calldata data) external payable override {
WebAuthnValidatorData memory pubKey = abi.decode(data, (WebAuthnValidatorData));
require(
webAuthnValidatorStorage[msg.sender][permissionId][kernel].x == 0
&& webAuthnValidatorStorage[msg.sender][permissionId][kernel].y == 0,
"WebAuthnSigner: kernel already registered"
);
require(pubKey.x != 0 && pubKey.y != 0, "WebAuthnSigner: invalid public key");
webAuthnValidatorStorage[msg.sender][permissionId][kernel] = pubKey;
}

function validateUserOp(address kernel, bytes32 permissionId, bytes32 userOpHash, bytes calldata signature)
external
payable
override
returns (ValidationData)
{
return _verifySignature(kernel, permissionId, userOpHash, signature);
}

function validateSignature(address kernel, bytes32 permissionId, bytes32 messageHash, bytes calldata signature)
external
view
override
returns (ValidationData)
{
return _verifySignature(kernel, permissionId, messageHash, signature);
}

function _verifySignature(address sender, bytes32 permissionId, bytes32 hash, bytes calldata signature)
private
view
returns (ValidationData)
{
(
bytes memory authenticatorData,
string memory clientDataJSON,
uint256 challengeLocation,
uint256 responseTypeLocation,
uint256 r,
uint256 s
) = abi.decode(signature, (bytes, string, uint256, uint256, uint256, uint256));

WebAuthnValidatorData memory pubKey = webAuthnValidatorStorage[msg.sender][permissionId][sender];
require(pubKey.x != 0 && pubKey.y != 0, "WebAuthnSigner: kernel not registered");

bool isValid = WebAuthn.verifySignature(
abi.encodePacked(hash),
authenticatorData,
true, // TODO: check if this needs to be true always
clientDataJSON,
challengeLocation,
responseTypeLocation,
r,
s,
pubKey.x,
pubKey.y
);

if (isValid) {
return ValidationData.wrap(0);
}

return SIG_VALIDATION_FAILED;
}
}