Skip to content

Commit

Permalink
verify key in playground & demo minifixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dagnelies committed Sep 23, 2024
1 parent 4b4e72d commit ea2ac1f
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 28 deletions.
4 changes: 2 additions & 2 deletions docs/demos/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
</p>
<hr/>
<p><b>Credential ID:</b> {{registrationParsed.credential.id}}</p>
<p><b>Public Key:</b> {{registrationParsed.credential.publicKey.substring(0,32)}}...</p>
<p><b>Public Key:</b> {{registrationParsed.credential.publicKey}}</p>
<p><b>Algorithm:</b> {{registrationParsed.credential.algorithm}}</p>
</section>

Expand All @@ -56,7 +56,7 @@
<b-tag type="is-danger" v-if="authenticationParsed.userVerified === false">No</b-tag>
</p>
<p><b>Credential ID:</b> {{authenticationParsed.credentialId}}</p>
<p><b>Signature:</b> {{authenticationParsed.signature.substring(0,32)}}...</p>
<p><b>Counter:</b> {{authenticationParsed.counter}}</p>
</section>

<hr/>
Expand Down
4 changes: 2 additions & 2 deletions docs/demos/conditional-ui.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@
</p>
<hr/>
<p><b>Credential ID:</b> {{registrationParsed.credential.id}}</p>
<p><b>Public Key:</b> {{registrationParsed.credential.publicKey.substring(0,32)}}...</p>
<p><b>Public Key:</b> {{registrationParsed.credential.publicKey}}</p>
<p><b>Algorithm:</b> {{registrationParsed.credential.algorithm}}</p>
</section>

<section v-if="authenticationParsed" style="text-align: left;">
<p><b>Credential ID:</b> {{authenticationParsed.credentialId}}</p>
<p><b>Signature:</b> {{authenticationParsed.signature.substring(0,32)}}...</p>
<p><b>Counter:</b> {{authenticationParsed.counter}}</p>
</section>

<hr/>
Expand Down
48 changes: 42 additions & 6 deletions docs/demos/js/playground.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,32 @@ const app = new Vue({
isValid: null
}
},
computed: {
parsedAuthData() {
const authData = this.verification.authenticatorData
if(!authData)
return null
try {
return webauthn.parsers.parseAuthenticator(authData)
}
catch(e) {
console.warn(e)
return "ERROR: failed to parse authenticator data. See console logs for more details."
}
},
parsedClientData() {
const clientData = this.verification.clientData
if(!clientData)
return null
try {
return webauthn.parsers.parseClient(clientData)
}
catch(e) {
console.warn(e)
return "ERROR: failed to parse client data. See console logs for more details."
}
}
},
methods: {
newChallenge() {
return webauthn.server.randomChallenge()
Expand Down Expand Up @@ -126,6 +152,22 @@ const app = new Vue({
})
}
},
async verifyPublicKey() {
const algorithm = this.verification.algorithm
const publicKey = this.verification.publicKey
if(!algorithm)
return window.alert('No algorithm defined!')
if(!publicKey)
return window.alert('Public key not defined!')
try {
const parsedKey = await webauthn.server.parseCryptoKey(algorithm, publicKey)
console.log(parsedKey)
return window.alert('Public key is VALID')
} catch (error) {
console.warn(error)
return window.alert('INVALID public key: see details in console logs')
}
},
async verifySignature() {
try {
this.verification.isValid = await webauthn.server.verifySignature(this.verification)
Expand All @@ -138,12 +180,6 @@ const app = new Vue({
})
this.verification.isValid = false
}
},
parseAuthData(authData) {
return webauthn.parsers.parseAuthenticator(authData)
},
parseClientData(clientData) {
return webauthn.parsers.parseClient(clientData)
}
}
})
4 changes: 2 additions & 2 deletions docs/demos/js/webauthn.min.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/demos/js/webauthn.min.js.map

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions docs/demos/playground.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,22 @@ <h2 class="title">Signature validation</h2>

<b-field label="PublicKey" horizontal>
<b-input v-model="verification.publicKey" type="textarea"></b-input>
<div class="hint">The public key created during registration.</div>
<div class="hint">
<p>The public key created during registration.</p>
<p><b-button @click="verifyPublicKey()">Verify public key</b-button></p>
</div>
</b-field>

<hr/>

<b-field label="AuthenticatorData" horizontal>
<b-input v-model="verification.authenticatorData" type="textarea"></b-input>
<div class="hint"><pre v-if="verification.authenticatorData">{{parseAuthData(verification.authenticatorData)}}</pre></div>
<div class="hint"><pre v-if="verification.authenticatorData">{{parsedAuthData}}</pre></div>
</b-field>

<b-field label="ClientData" horizontal>
<b-input v-model="verification.clientData" type="textarea"></b-input>
<div class="hint"><pre v-if="verification.clientData">{{parseClientData(verification.clientData)}}</pre></div>
<div class="hint"><pre v-if="verification.clientData">{{parsedClientData}}</pre></div>
</b-field>

<b-field label="Signature" horizontal>
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@passwordless-id/webauthn",
"version": "2.1.1",
"version": "2.1.2",
"description": "A small wrapper around the webauthn protocol to make one's life easier.",

"type": "module",
Expand All @@ -14,8 +14,8 @@
"scripts": {
"build": "npm run build-module && npm run build-nodejs && npm run build-browser && npm run build-demos",
"build-module": "tsc",
"build-nodejs": "esbuild src/index.ts --platform=node --bundle --banner:js=/*passwordless-id/[email protected].1*/ --outfile=dist/cjs/webauthn.cjs",
"build-browser": "esbuild src/index.ts --platform=browser --bundle --banner:js=/*passwordless-id/[email protected].1*/ --format=esm --minify --sourcemap --outfile=dist/browser/webauthn.min.js",
"build-nodejs": "esbuild src/index.ts --platform=node --bundle --banner:js=/*passwordless-id/[email protected].2*/ --outfile=dist/cjs/webauthn.cjs",
"build-browser": "esbuild src/index.ts --platform=browser --bundle --banner:js=/*passwordless-id/[email protected].2*/ --format=esm --minify --sourcemap --outfile=dist/browser/webauthn.min.js",
"build-demos": "cp dist/browser/*.js docs/demos/js; cp dist/browser/*.js.map docs/demos/js",
"test": "jest",
"dev": "mkdocs serve"
Expand Down
4 changes: 3 additions & 1 deletion src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ export async function authenticate(options: AuthenticateOptions): Promise<Authen

if(ongoingAuth != null)
ongoingAuth.abort('Cancel ongoing authentication')
ongoingAuth = new AbortController();

if(options.autocomplete)
ongoingAuth = new AbortController();

const raw = await navigator.credentials.get({
publicKey: authOptions,
Expand Down
13 changes: 7 additions & 6 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ User agents MUST be able to return a non-null value for getPublicKey() when the
-8 (EdDSA), where crv is 6 (Ed25519).
*/
function getAlgoParams(algorithm: NamedAlgo): any {
function getAlgoParams(algorithm: NamedAlgo): AlgoParams {
switch (algorithm) {
case 'RS256':
return {
Expand All @@ -149,9 +149,10 @@ function getAlgoParams(algorithm: NamedAlgo): any {
}
}

type AlgoParams = AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm
type AlgoParams = RsaPssParams | EcKeyImportParams | EcdsaParams

async function parseCryptoKey(algoParams: AlgoParams, publicKey: string): Promise<CryptoKey> {
export async function parseCryptoKey(algorithm: NamedAlgo, publicKey: string): Promise<CryptoKey> {
const algoParams = getAlgoParams(algorithm)
const buffer = utils.parseBase64url(publicKey)
return crypto.subtle.importKey('spki', buffer, algoParams, false, ['verify'])
}
Expand Down Expand Up @@ -180,8 +181,7 @@ type VerifyParams = {
*/
// see also https://gist.github.com/philholden/50120652bfe0498958fd5926694ba354
export async function verifySignature({ algorithm, publicKey, authenticatorData, clientData, signature, verbose }: VerifyParams): Promise<boolean> {
const algoParams = getAlgoParams(algorithm)
let cryptoKey = await parseCryptoKey(algoParams, publicKey)
let cryptoKey = await parseCryptoKey(algorithm, publicKey)

if(verbose) {
console.debug(cryptoKey)
Expand All @@ -193,7 +193,7 @@ export async function verifySignature({ algorithm, publicKey, authenticatorData,
let comboBuffer = utils.concatenateBuffers(utils.parseBase64url(authenticatorData), clientHash)

if(verbose) {
console.debug('Crypto Algo: ' + JSON.stringify(algoParams))
console.debug('Algorithm: ' + algorithm)
console.debug('Public key: ' + publicKey)
console.debug('Data: ' + utils.toBase64url(comboBuffer))
console.debug('Signature: ' + signature)
Expand All @@ -204,6 +204,7 @@ export async function verifySignature({ algorithm, publicKey, authenticatorData,
if(algorithm == 'ES256')
signatureBuffer = convertASN1toRaw(signatureBuffer)

const algoParams = getAlgoParams(algorithm)
const isValid = await crypto.subtle.verify(algoParams, cryptoKey, signatureBuffer, comboBuffer)

return isValid
Expand Down

0 comments on commit ea2ac1f

Please sign in to comment.