From d699a74527d718adbb532daecafacc8530aacf48 Mon Sep 17 00:00:00 2001 From: Sahil Vasava Date: Thu, 15 Feb 2024 17:50:53 +0700 Subject: [PATCH] feat: added WebAuthnSigner for ModularPermissionValidator --- .gitignore | 1 + .gitmodules | 3 + lib/p256-verifier | 1 + .../signers/WebAuthnSigner.sol | 82 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 160000 lib/p256-verifier create mode 100644 src/validator/modularPermission/signers/WebAuthnSigner.sol diff --git a/.gitignore b/.gitignore index 3978feff..cfe668b2 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ artifacts-selected cache_hardhat lcov.info +settings.json \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 744ac54b..467f62e8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/lib/p256-verifier b/lib/p256-verifier new file mode 160000 index 00000000..29475ae3 --- /dev/null +++ b/lib/p256-verifier @@ -0,0 +1 @@ +Subproject commit 29475ae300ec95d98d5c7cc34c094846f0aa2dcd diff --git a/src/validator/modularPermission/signers/WebAuthnSigner.sol b/src/validator/modularPermission/signers/WebAuthnSigner.sol new file mode 100644 index 00000000..011088fe --- /dev/null +++ b/src/validator/modularPermission/signers/WebAuthnSigner.sol @@ -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; + } +}