-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathWebAuthnSigner.sol
More file actions
145 lines (128 loc) · 4.82 KB
/
WebAuthnSigner.sol
File metadata and controls
145 lines (128 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "src/base/SignerBase.sol";
import {SIG_VALIDATION_SUCCESS_UINT, SIG_VALIDATION_FAILED_UINT} from "src/types/Constants.sol";
import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";
import {ERC1271_MAGICVALUE, ERC1271_INVALID} from "src/types/Constants.sol";
import {WebAuthn} from "src/utils/WebAuthn.sol";
struct WebAuthnSignerData {
uint256 pubKeyX;
uint256 pubKeyY;
}
/**
* @title WebAuthnSigner
* @notice This signer uses the P256 curve to validate signatures.
*/
contract WebAuthnSigner is SignerBase {
// The location of the challenge in the clientDataJSON
uint256 constant CHALLENGE_LOCATION = 23;
// Emitted when a bad key is provided.
error InvalidPublicKey();
// Emitted when the public key of a kernel is changed.
event WebAuthnRegistered(address indexed kernel, uint256 pubKeyX, uint256 pubKeyY);
mapping(address => uint256) public usedIds;
// The P256 public keys of a kernel.
mapping(bytes32 id => mapping(address kernel => WebAuthnSignerData)) public webAuthnSignerStorage;
function isInitialized(address kernel) external view returns (bool) {
return _isInitialized(kernel);
}
function _isInitialized(address kernel) internal view returns (bool) {
return usedIds[kernel] > 0;
}
/**
* @notice Validate a user operation.
*/
function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
override
returns (uint256)
{
return _verifySignature(id, msg.sender, userOpHash, userOp.signature);
}
/**
* @notice Verify a signature with sender for ERC-1271 validation.
*/
function checkSignature(bytes32 id, address, bytes32 hash, bytes calldata sig)
external
view
override
returns (bytes4)
{
return _verifySignature(id, msg.sender, hash, sig) == SIG_VALIDATION_SUCCESS_UINT
? ERC1271_MAGICVALUE
: ERC1271_INVALID;
}
/**
* @notice Verify a signature.
*/
function _verifySignature(bytes32 id, address account, bytes32 hash, bytes calldata signature)
private
view
returns (uint256)
{
// decode the signature
(
bytes memory authenticatorData,
string memory clientDataJSON,
uint256 responseTypeLocation,
uint256 r,
uint256 s,
bool usePrecompiled
) = abi.decode(signature, (bytes, string, uint256, uint256, uint256, bool));
// get the public key from storage
WebAuthnSignerData memory webAuthnData = webAuthnSignerStorage[id][account];
// verify the signature using the signature and the public key
bool isValid = WebAuthn.verifySignature(
abi.encodePacked(hash),
authenticatorData,
true,
clientDataJSON,
CHALLENGE_LOCATION,
responseTypeLocation,
r,
s,
webAuthnData.pubKeyX,
webAuthnData.pubKeyY,
usePrecompiled
);
// return the validation data
if (isValid) {
return SIG_VALIDATION_SUCCESS_UINT;
}
return SIG_VALIDATION_FAILED_UINT;
}
/**
* @notice Install WebAuthn signer for a kernel account.
* @dev The kernel account need to be the `msg.sender`.
* @dev The public key is encoded as `abi.encode(WebAuthnSignerData)` inside the data, so (uint256,uint256).
*/
function _signerOninstall(bytes32 id, bytes calldata _data) internal override {
// check if this specific id is already initialized
if (webAuthnSignerStorage[id][msg.sender].pubKeyX != 0) {
revert AlreadyInitialized(msg.sender);
}
usedIds[msg.sender]++;
// check validity of the public key
(WebAuthnSignerData memory webAuthnData,) = abi.decode(_data, (WebAuthnSignerData, bytes32));
if (webAuthnData.pubKeyX == 0 || webAuthnData.pubKeyY == 0) {
revert InvalidPublicKey();
}
// Update the key (so a sstore)
webAuthnSignerStorage[id][msg.sender] = webAuthnData;
// And emit the event
emit WebAuthnRegistered(msg.sender, webAuthnData.pubKeyX, webAuthnData.pubKeyY);
}
/**
* @notice Uninstall WebAuthn validator for a kernel account.
* @dev The kernel account need to be the `msg.sender`.
*/
function _signerOnUninstall(bytes32 id, bytes calldata) internal override {
// check if this specific id is initialized
if (webAuthnSignerStorage[id][msg.sender].pubKeyX == 0) {
revert NotInitialized(msg.sender);
}
delete webAuthnSignerStorage[id][msg.sender];
usedIds[msg.sender]--;
}
}