This repository was archived by the owner on Aug 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 459
web-authn support #577
Merged
Merged
web-authn support #577
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
849c039
Merge pull request #528 from EOSIO/develop
c0d3ster 240501e
wa pub key
tbfleming a56a8bc
wa
tbfleming 7043c7a
Merge remote-tracking branch 'origin/develop' into wa-experiment
tbfleming 488dd46
wa
tbfleming b8aeb30
wa
tbfleming 0acd10e
wa
tbfleming 271f9f7
adding resolutions for nested dependency vulnerabilities
8ad58dd
Merge remote-tracking branch 'origin/develop' into wa-experiment
tbfleming ea1634f
Merge remote-tracking branch 'origin/dependency-update' into wa-exper…
tbfleming 6070a2e
WebAuthnSignatureProvider
tbfleming File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/** | ||
* @module WebAuthn-Sig | ||
*/ | ||
// copyright defined in eosjs/LICENSE.txt | ||
|
||
import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces'; | ||
import * as ser from './eosjs-serialize'; | ||
import * as numeric from './eosjs-numeric'; | ||
import { ec } from 'elliptic'; | ||
|
||
/** Signs transactions using WebAuthn */ | ||
export class WebAuthnSignatureProvider implements SignatureProvider { | ||
/** Map public key to credential ID (hex). User must populate this. */ | ||
public keys = new Map<string, string>(); | ||
|
||
/** Public keys that the `SignatureProvider` holds */ | ||
public async getAvailableKeys() { | ||
return Array.from(this.keys.keys()); | ||
} | ||
|
||
/** Sign a transaction */ | ||
public async sign( | ||
{ chainId, requiredKeys, serializedTransaction, serializedContextFreeData }: | ||
SignatureProviderArgs, | ||
) { | ||
const signBuf = new ser.SerialBuffer(); | ||
signBuf.pushArray(ser.hexToUint8Array(chainId)); | ||
signBuf.pushArray(serializedTransaction); | ||
if (serializedContextFreeData) { | ||
signBuf.pushArray(new Uint8Array(await crypto.subtle.digest('SHA-256', serializedContextFreeData.buffer))); | ||
} else { | ||
signBuf.pushArray(new Uint8Array(32)); | ||
} | ||
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', signBuf.asUint8Array().slice().buffer)); | ||
|
||
const signatures = [] as string[]; | ||
for (const key of requiredKeys) { | ||
const id = ser.hexToUint8Array(this.keys.get(key)); | ||
const assertion = await (navigator as any).credentials.get({ | ||
jeffreyssmith2nd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
publicKey: { | ||
timeout: 60000, | ||
allowCredentials: [{ | ||
id, | ||
type: 'public-key', | ||
}], | ||
challenge: digest.buffer, | ||
}, | ||
}); | ||
const e = new ec('p256') as any; | ||
const pubKey = e.keyFromPublic(numeric.stringToPublicKey(key).data.subarray(0, 33)).getPublic(); | ||
|
||
const fixup = (x: Uint8Array) => { | ||
const a = Array.from(x); | ||
while (a.length < 32) { | ||
a.unshift(0); | ||
} | ||
while (a.length > 32) { | ||
if (a.shift() !== 0) { | ||
throw new Error('Signature has an r or s that is too big'); | ||
} | ||
} | ||
return new Uint8Array(a); | ||
}; | ||
|
||
const der = new ser.SerialBuffer({ array: new Uint8Array(assertion.response.signature) }); | ||
if (der.get() !== 0x30) { | ||
throw new Error('Signature missing DER prefix'); | ||
} | ||
if (der.get() !== der.array.length - 2) { | ||
throw new Error('Signature has bad length'); | ||
} | ||
if (der.get() !== 0x02) { | ||
throw new Error('Signature has bad r marker'); | ||
} | ||
const r = fixup(der.getUint8Array(der.get())); | ||
if (der.get() !== 0x02) { | ||
throw new Error('Signature has bad s marker'); | ||
} | ||
const s = fixup(der.getUint8Array(der.get())); | ||
|
||
const whatItReallySigned = new ser.SerialBuffer(); | ||
whatItReallySigned.pushArray(new Uint8Array(assertion.response.authenticatorData)); | ||
whatItReallySigned.pushArray(new Uint8Array( | ||
await crypto.subtle.digest('SHA-256', assertion.response.clientDataJSON))); | ||
const hash = new Uint8Array( | ||
await crypto.subtle.digest('SHA-256', whatItReallySigned.asUint8Array().slice())); | ||
const recid = e.getKeyRecoveryParam(hash, new Uint8Array(assertion.response.signature), pubKey); | ||
|
||
const sigData = new ser.SerialBuffer(); | ||
sigData.push(recid + 27 + 4); | ||
sigData.pushArray(r); | ||
sigData.pushArray(s); | ||
sigData.pushBytes(new Uint8Array(assertion.response.authenticatorData)); | ||
sigData.pushBytes(new Uint8Array(assertion.response.clientDataJSON)); | ||
|
||
const sig = numeric.signatureToString({ | ||
type: numeric.KeyType.wa, | ||
data: sigData.asUint8Array().slice(), | ||
}); | ||
signatures.push(sig); | ||
} | ||
return { signatures, serializedTransaction, serializedContextFreeData }; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.