Add U2F support

This commit is contained in:
Jonas Lochmann
2022-09-22 08:47:06 +02:00
parent 04aa2ce517
commit 613776cbf9
64 changed files with 2501 additions and 134 deletions
+32
View File
@@ -0,0 +1,32 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export function intToBuffer(input: number): Buffer {
const buffer = Buffer.alloc(4)
buffer.writeUInt32BE(input)
return buffer
}
export function longToBuffer(input: bigint): Buffer {
const buffer = Buffer.alloc(8)
buffer.writeBigUInt64BE(input)
return buffer
}
+52
View File
@@ -0,0 +1,52 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2022 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { createVerify, createPublicKey, createHash } from 'crypto'
export function isU2fSignatureValid({
u2fRawResponse, applicationId, challenge, publicKey
}: {
u2fRawResponse: Buffer
applicationId: Buffer
challenge: Buffer
publicKey: Buffer
}): boolean {
if (u2fRawResponse.length < 5) return false
if (publicKey.length !== 65 || publicKey.readInt8(0) !== 4) return false
const publicKeyObject = createPublicKey({
key: Buffer.concat([
Buffer.from('MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA=', 'base64'), publicKey
]),
format: 'der',
type: 'spki'
})
const verifier = createVerify('SHA256')
verifier.update(applicationId)
verifier.update(u2fRawResponse.slice(0, 5))
verifier.update(challenge)
return verifier.verify(publicKeyObject, u2fRawResponse.slice(5))
}
export function calculateApplicationId(url: string): Buffer {
return createHash('sha256')
.update(Buffer.from(url, 'utf8'))
.digest()
}