Skip to content

Commit

Permalink
Add WebAuthnMetadata struct
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed Nov 6, 2024
1 parent eef8c4f commit c3bb7e3
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 4 deletions.
47 changes: 43 additions & 4 deletions src/utils/WebAuthn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,30 @@ library WebAuthn {
// The WebAuthn client data JSON.
// See: https://www.w3.org/TR/webauthn-2/#dom-authenticatorresponse-clientdatajson.
string clientDataJSON;
// The index at which "challenge":"..." occurs in `clientDataJSON`.
// Start index of "challenge":"..." in `clientDataJSON`.
uint256 challengeIndex;
// The index at which "type":"..." occurs in `clientDataJSON`.
// Start index of "type":"..." in `clientDataJSON`.
uint256 typeIndex;
// The r value of secp256r1 signature
// The r value of secp256r1 signature.
bytes32 r;
// The s value of secp256r1 signature
// The s value of secp256r1 signature.
bytes32 s;
}

/// @dev Alternative struct for verification (Ithaca style).
struct WebAuthnMetadata {
// The WebAuthn authenticator data.
bytes authenticatorData;
// The WebAuthn client data JSON.
string clientDataJSON;
// Start index of "challenge":"..." in `clientDataJSON`.
uint256 challengeIndex;
// Start index of "type":"..." in `clientDataJSON`.
uint256 typeIndex;
// Whether to check that the "User Verified" flag in `authenticatorData` is set.
bool requireUserVerification;
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down Expand Up @@ -159,6 +173,31 @@ library WebAuthn {
return result && P256.verifySignature(messageHash, auth.r, auth.s, x, y);
}

/// @dev Alternative syntax for verification (Ithaca style).
function verify(
bytes memory challenge,
WebAuthnMetadata memory metadata,
bytes32 r,
bytes32 s,
bytes32 x,
bytes32 y
) internal view returns (bool) {
return verify(
challenge,
metadata.requireUserVerification,
WebAuthnAuth(
metadata.authenticatorData,
metadata.clientDataJSON,
metadata.challengeIndex,
metadata.typeIndex,
r,
s
),
x,
y
);
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ENCODING / DECODING HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down
42 changes: 42 additions & 0 deletions test/WebAuthn.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ contract WebAuthnTest is P256VerifierEtcher {
assertTrue(WebAuthn.verify(t.challenge, false, auth, t.x, t.y));
}

function testSafariAltSyntax() public {
_etchRIPPrecompile(true);
_etchVerifier(true);
_TestTemps memory t = _testTemps();
WebAuthn.WebAuthnMetadata memory metadata;
metadata.authenticatorData =
hex"49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000101";
metadata.clientDataJSON = string(
abi.encodePacked(
'{"type":"webauthn.get","challenge":"',
Base64.encode(t.challenge, true, true),
'","origin":"http://localhost:3005"}'
)
);
metadata.challengeIndex = 23;
metadata.typeIndex = 1;
bytes32 r = 0x60946081650523acad13c8eff94996a409b1ed60e923c90f9e366aad619adffa;
bytes32 s = 0x3216a237b73765d01b839e0832d73474bc7e63f4c86ef05fbbbfbeb34b35602b;
assertTrue(WebAuthn.verify(t.challenge, metadata, r, s, t.x, t.y));
}

function testChrome() public {
_etchRIPPrecompile(true);
_etchVerifier(true);
Expand All @@ -72,6 +93,27 @@ contract WebAuthnTest is P256VerifierEtcher {
assertTrue(WebAuthn.verify(t.challenge, false, auth, t.x, t.y));
}

function testChromeAltSyntax() public {
_etchRIPPrecompile(true);
_etchVerifier(true);
_TestTemps memory t = _testTemps();
WebAuthn.WebAuthnMetadata memory metadata;
metadata.authenticatorData =
hex"49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d9763050000010a";
metadata.clientDataJSON = string(
abi.encodePacked(
'{"type":"webauthn.get","challenge":"',
Base64.encode(t.challenge, true, true),
'","origin":"http://localhost:3005","crossOrigin":false}'
)
);
metadata.challengeIndex = 23;
metadata.typeIndex = 1;
bytes32 r = 0x41c01ca5ecdfeb23ef70d6cc216fd491ac3aa3d40c480751f3618a3a9ef67b41;
bytes32 s = 0x6595569abf76c2777e832a9252bae14efdb77febd0fa3b919aa16f6208469e86;
assertTrue(WebAuthn.verify(t.challenge, metadata, r, s, t.x, t.y));
}

function testPassthroughDifferential(bytes32) public {
_etchVerifierPassthrough(true);
_etchRIPPrecompilePassthrough(true);
Expand Down

0 comments on commit c3bb7e3

Please sign in to comment.