Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(WebAuthn): add an option for user verification #25

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,21 @@ user.
- An object mapping, where the key is the name of a property from the
registration request to be included in the user object and the value is the
name of that property on the user object.
- `[store = MemoryAdapter]` - The storage interface for user objects. Defaults
- `[store = MemoryAdapter]` - the storage interface for user objects. Defaults
to an object in memory (for testing only).
- `[attestation = 'none']` - the [attestation conveyance preference](
https://w3c.github.io/webauthn/#enum-attestation-convey). Setting this to
anything other than `'none'` will require attestation and validate it.
- `[requireUserVerification = false]` - whether to require [user verification](
https://w3c.github.io/webauthn/#user-verification).
- `[credentialEndpoint = '/register']` - the path of the credential attestation
challenge endpoint.
- `[assertionEndpoint = '/login']` - the path of the challenge assertion
endpoint.
- `[challengeEndpoint = '/response']` - the path of the challenge response
endpoint.
- `[logoutEndpoint = '/logout']` - the path of the logout endpoint.
- `[enableLogging = true]` - Enable or disable logging to stdout.
- `[enableLogging = true]` - enable or disable logging to stdout.

**`webauthn.initialize()`**

Expand Down
27 changes: 20 additions & 7 deletions src/Webauthn.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Webauthn {
enableLogging: true,
attestation: Dictionaries.AttestationConveyancePreference.NONE,
authenticator: Dictionaries.AuthenticatorAttachment.CROSS_PLATFORM,
requireUserVerification: false,
}, options)

const attestationOptions = Object.values(Dictionaries.AttestationConveyancePreference)
Expand Down Expand Up @@ -118,6 +119,9 @@ class Webauthn {
if (this.config.enableLogging) console.log('STORED')

const attestation = new AttestationChallengeBuilder(this)
.setUserVerification(this.config.requireUserVerification ?
Dictionaries.UserVerificationRequirement.REQUIRED
: Dictionaries.UserVerificationRequirement.DISCOURAGED)
.setUserInfo(user)
.setAttestationType(this.config.attestation)
.setAuthenticator(this.config.authenticator)
Expand Down Expand Up @@ -261,7 +265,7 @@ class Webauthn {
}

} else if (response.authenticatorData !== undefined) {
result = Webauthn.verifyAuthenticatorAssertionResponse(response, user.authenticator, this.config.enableLogging)
result = this.verifyAuthenticatorAssertionResponse(response, user.authenticator)

if (result.verified) {
if (result.counter <= user.authenticator.counter)
Expand Down Expand Up @@ -359,8 +363,13 @@ class Webauthn {
const authrDataStruct = Webauthn.parseMakeCredAuthData(ctapMakeCredResp.authData);
if (this.config.enableLogging) console.log('AUTHR_DATA_STRUCT', authrDataStruct)

if (!(authrDataStruct.flags & 0x01)) // U2F_USER_PRESENTED
throw new Error('User was NOT presented durring authentication!');
if (!(authrDataStruct.flags & 0x01)) // U2F_USER_PRESENT
throw new Error('User was not present during authentication!');

if (this.config.requireUserVerification && !(authrDataStruct.flags & 0x04)) {// U2F_USER_VERIFIED
throw new Error('User was not verified during authentication!')
}


const publicKey = Webauthn.COSEECDHAtoPKCS(authrDataStruct.COSEPublicKey)

Expand Down Expand Up @@ -475,16 +484,20 @@ class Webauthn {
return response
}

static verifyAuthenticatorAssertionResponse (webauthnResponse, authr, enableLogging = false) {
verifyAuthenticatorAssertionResponse (webauthnResponse, authr) {
const authenticatorData = base64url.toBuffer(webauthnResponse.authenticatorData)

const response = { 'verified': false }
if (['fido-u2f'].includes(authr.fmt)) {
const authrDataStruct = Webauthn.parseGetAssertAuthData(authenticatorData)
if (enableLogging) console.log('AUTH_DATA', authrDataStruct)
if (this.config.enableLogging) console.log('AUTH_DATA', authrDataStruct)

if (!(authrDataStruct.flags & 0x01)) {// U2F_USER_PRESENT
throw new Error('User was not present during authentication!')
}

if (!(authrDataStruct.flags & 0x01)) {// U2F_USER_PRESENTED
throw new Error('User was not presented durring authentication!')
if (this.config.requireUserVerification && !(authrDataStruct.flags & 0x04)) {// U2F_USER_VERIFIED
throw new Error('User was not verified during authentication!')
}

const clientDataHash = Webauthn.hash(base64url.toBuffer(webauthnResponse.clientDataJSON))
Expand Down