Laragear / WebAuthn

Authenticate users with Passkeys: fingerprints, patterns and biometric data.
MIT License
295 stars 37 forks source link

[3.x] Signing #80

Closed illambo closed 4 months ago

illambo commented 4 months ago

Please check these requirements

Description

"While WebAuthn was designed primarily for authentication, the framework can be extended to support signing with keypairs generated on authenticators without requiring custom clients for end users."

I found this functionality very interesting, the flow is described here:

"In short, the registration and authentication events consists of a cryptographic signing process with the public key returned, which is then used to sign a data set which is provided by the relying party. Replacing the randomly generated challenge with a hash of a file to be signed allows this signature flow to be applied to actual documentation, with the public key also available for verification after the fact."

Currently the related discuss and progress in this regard under webauthn / webcrypto are in a sort of "limbo" (see https://github.com/w3c/webauthn/issues/1608 and related https://github.com/w3c/webcrypto/issues/263) so I have the thought there would be room for use currently.

Interesting also this caveats to keep in mind.

On the implementation side, I think it would be enough to give the possibility to inject the ByteBuffer into AssertionCreation and then use it as an alternative for the creation of the Challenge (instead of random).

What do you think about it?

Code sample

$assertion = app()->make(AssertionCreator::class)
 ->send(new AssertionCreation(
  user: null,
  userVerification: UserVerification::DISCOURAGED,
  challengeData: new ByteBuffer('...hash_of_a_file...')
 ))
 ->then(static function (AssertionCreation $creation): Responsable {
  return $creation->json;
 });
DarkGhostHunter commented 4 months ago

Currently you can add a new pipe to the ceremony pipeline to capture the challenge and re-save it with your own Bytestream. Challenge validation shouldn't be affected.

Since the 3.x allows to have a custom Challenge Repository, you may modify the challenge byte stream with a document hash for the given user.

If you care about determinism, you can encrypt the document hash with the app key, which always returns a different encrypted, but large, string.

I personally think this scenario is very niche and not mainstream, so I'll leave that as-is. I honestly think most users will want to use a Passkey on their devices without without limitations.

Securer apps will want to create their own ceremony workflows, which escapes this library purpose, even if it can be used as a basis for such implementation.

DarkGhostHunter commented 4 months ago

Buuuuuuuuuut... in 2.x this can be easily implemented in my end by just simply checking if the Challenge exist and not replace it if found.

illambo commented 4 months ago

Ok thanks for the suggestion.

illambo commented 4 months ago

In the end the solution I found most convenient (in v3.x) is to replace the Assertion\Creator\Pipes\CreateAssertionChallenge pipe with a custom one by binding it to the provider and extending Assertion\Creator\AssertionCreation class with custom data (in this way I avoid unnecessary push/pull on the challenge repository).

DarkGhostHunter commented 4 months ago

I see... I'll make a PR there to use an existing challenge, and add data to the challenge in a separate line. This way you don't need override pipes since these can change between minor or patch versions.

illambo commented 4 months ago

Ok I understand, thanks! If you don't find a comfortable or linear solution, don't worry.

DarkGhostHunter commented 4 months ago

Try the latest commit to 3.x

illambo commented 4 months ago

Perfect, it works and simplifies the objective of the topic, thanks again.