diff options
author | Matthew Miller <matthew@millerti.me> | 2022-11-11 15:46:06 -0800 |
---|---|---|
committer | Matthew Miller <matthew@millerti.me> | 2022-11-11 15:46:06 -0800 |
commit | 0c0c09687b3308dd1c680bb18f37393a6f6d616c (patch) | |
tree | fd26d8c9428b41427352b5bdb95c1b8d430cec63 | |
parent | 248bd4c205d873bcf31d6374034d8d04f94496e5 (diff) |
Replace some more references to Buffer
13 files changed, 122 insertions, 90 deletions
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts index 3b8e7b6..66163dc 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts @@ -1,4 +1,3 @@ -import base64url from 'base64url'; import { verifyAuthenticationResponse } from './verifyAuthenticationResponse'; import * as esmDecodeClientDataJSON from '../helpers/decodeClientDataJSON'; @@ -8,6 +7,8 @@ import { AuthenticatorDevice, AuthenticationCredentialJSON, } from '@simplewebauthn/typescript-types'; +import * as uint8Array from '../helpers/uint8array'; +import * as base64url from '../helpers/base64url'; let mockDecodeClientData: jest.SpyInstance; let mockParseAuthData: jest.SpyInstance; @@ -183,7 +184,7 @@ test('should throw an error if user verification is required but user was not ve // TODO: Get a real TPM authentication response in here test.skip('should verify TPM assertion', async () => { const expectedChallenge = 'dG90YWxseVVuaXF1ZVZhbHVlRXZlcnlBc3NlcnRpb24'; - jest.spyOn(base64url, 'encode').mockReturnValueOnce(expectedChallenge); + jest.spyOn(base64url, 'toString').mockReturnValueOnce(expectedChallenge); const verification = await verifyAuthenticationResponse({ credential: { id: 'YJ8FMM-AmcUt73XPX341WXWd7ypBMylGjjhu0g3VzME', @@ -279,7 +280,7 @@ test('should pass verification if custom challenge verifier returns true', async }, expectedChallenge: (challenge: string) => { const parsedChallenge: { actualChallenge: string; arbitraryData: string } = JSON.parse( - base64url.decode(challenge), + base64url.toString(challenge), ); return parsedChallenge.actualChallenge === 'K3QxOjnVJLiGlnVEp5va5QJeMVWNf_7PYgutgbAtAUA'; }, @@ -318,7 +319,7 @@ test('should return authenticator extension output', async () => { clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVpzVkN6dHJEVzdEMlVfR0hDSWxZS0x3VjJiQ3NCVFJxVlFVbkpYbjlUayIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOmd4N3NxX3B4aHhocklRZEx5ZkcwcHhLd2lKN2hPazJESlE0eHZLZDQzOFEiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZmlkby5leGFtcGxlLmZpZG8yYXBpZXhhbXBsZSJ9', authenticatorData: - 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFvZGV2aWNlUHVibGljS2V5pWNkcGtYTaUBAgMmIAEhWCCZGqvtneQnGp7erYgG-dyW1tzNDEdiU6VRBInsg3m-WyJYIKCXPP3tu3nif-9O50gWc_szElBN3KVDTP0jQx1q0p7aY3NpZ1hHMEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPhlbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng=', + 'DXX8xWP9p3nbLjQ-6kiYiHWLeFSdSTpP2-oc2WqjHMSFAAAAAKFsZGV2aWNlUHViS2V5pWNkcGtYTaUBAgMmIAEhWCCZGqvtneQnGp7erYgG-dyW1tzNDEdiU6VRBInsg3m-WyJYIKCXPP3tu3nif-9O50gWc_szElBN3KVDTP0jQx1q0p7aY3NpZ1hHMEUCIElSbNKK72tOYhp9WTbStQSVL8CuIxOk8DV6r_-uqWR0AiEAnVE6yu-wsyx2Wq5v66jClGhe_2P_HL8R7PIQevT-uPhlbm9uY2VAZXNjb3BlQQBmYWFndWlkULk_2WHy5kYvsSKCACJH3ng', signature: 'MEYCIQDlRuxY7cYre0sb3T6TovQdfYIUb72cRZYOQv_zS9wN_wIhAOvN-fwjtyIhWRceqJV4SX74-z6oALERbC7ohk8EdVPO', userHandle: 'b2FPajFxcmM4MWo3QkFFel9RN2lEakh5RVNlU2RLNDF0Sl92eHpQYWV5UQ==', @@ -343,18 +344,16 @@ test('should return authenticator extension output', async () => { }); expect(verification.authenticationInfo?.authenticatorExtensionResults).toMatchObject({ - devicePublicKey: { - dpk: Buffer.from( + devicePubKey: { + dpk: uint8Array.fromHex( 'A5010203262001215820991AABED9DE4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA', - 'hex', ), - sig: Buffer.from( + sig: uint8Array.fromHex( '3045022049526CD28AEF6B4E621A7D5936D2B504952FC0AE2313A4F0357AAFFFAEA964740221009D513ACAEFB0B32C765AAE6FEBA8C294685EFF63FF1CBF11ECF2107AF4FEB8F8', - 'hex', ), - nonce: Buffer.from('', 'hex'), - scope: Buffer.from('00', 'hex'), - aaguid: Buffer.from('B93FD961F2E6462FB12282002247DE78', 'hex'), + nonce: uint8Array.fromHex(''), + scope: uint8Array.fromHex('00'), + aaguid: uint8Array.fromHex('B93FD961F2E6462FB12282002247DE78'), }, }); }); @@ -392,7 +391,7 @@ const assertionResponse: AuthenticationCredentialJSON = { clientExtensionResults: {}, type: 'public-key', }; -const assertionChallenge = base64url.encode('totallyUniqueValueEveryTime'); +const assertionChallenge = base64url.fromString('totallyUniqueValueEveryTime'); const assertionOrigin = 'https://dev.dontneeda.pw'; const authenticator: AuthenticatorDevice = { @@ -421,7 +420,7 @@ const assertionFirstTimeUsedResponse: AuthenticationCredentialJSON = { type: 'public-key', clientExtensionResults: {}, }; -const assertionFirstTimeUsedChallenge = base64url.encode('totallyUniqueValueEveryAssertion'); +const assertionFirstTimeUsedChallenge = base64url.fromString('totallyUniqueValueEveryAssertion'); const assertionFirstTimeUsedOrigin = 'https://dev.dontneeda.pw'; const authenticatorFirstTimeUsed: AuthenticatorDevice = { credentialPublicKey: base64url.toBuffer( diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts index c89d39b..9f52d70 100644 --- a/packages/server/src/authentication/verifyAuthenticationResponse.ts +++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts @@ -149,14 +149,14 @@ export async function verifyAuthenticationResponse( // Make sure the response's RP ID is ours if (typeof expectedRPID === 'string') { - const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii')); + const expectedRPIDHash = toHash(uint8Array.fromASCIIString(expectedRPID)); if (!uint8Array.areEqual(rpIdHash, expectedRPIDHash)) { throw new Error(`Unexpected RP ID hash`); } } else { // Go through each expected RP ID and try to find one that matches const foundMatch = expectedRPID.some(expected => { - const expectedRPIDHash = toHash(Buffer.from(expected, 'ascii')); + const expectedRPIDHash = toHash(uint8Array.fromASCIIString(expected)); return uint8Array.areEqual(rpIdHash, expectedRPIDHash); }); @@ -195,7 +195,7 @@ export async function verifyAuthenticationResponse( } const clientDataHash = toHash(base64url.toBuffer(response.clientDataJSON)); - const signatureBase = Buffer.concat([authDataBuffer, clientDataHash]); + const signatureBase = uint8Array.concat([authDataBuffer, clientDataHash]); const signature = base64url.toBuffer(response.signature); @@ -251,7 +251,7 @@ export async function verifyAuthenticationResponse( export type VerifiedAuthenticationResponse = { verified: boolean; authenticationInfo: { - credentialID: Buffer; + credentialID: Uint8Array; newCounter: number; userVerified: boolean; credentialDeviceType: CredentialDeviceType; diff --git a/packages/server/src/helpers/__mocks__/generateChallenge.ts b/packages/server/src/helpers/__mocks__/generateChallenge.ts index a339e56..d9d866e 100644 --- a/packages/server/src/helpers/__mocks__/generateChallenge.ts +++ b/packages/server/src/helpers/__mocks__/generateChallenge.ts @@ -1,3 +1,3 @@ -export function generateChallenge(): Buffer { - return Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); +export function generateChallenge(): Uint8Array { + return Uint8Array.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]); } diff --git a/packages/server/src/helpers/getCertificateInfo.ts b/packages/server/src/helpers/getCertificateInfo.ts index 02183c5..e503f70 100644 --- a/packages/server/src/helpers/getCertificateInfo.ts +++ b/packages/server/src/helpers/getCertificateInfo.ts @@ -36,7 +36,7 @@ const issuerSubjectIDKey: { [key: string]: 'C' | 'O' | 'OU' | 'CN' } = { * * @param pemCertificate Result from call to `convertASN1toPEM(x5c[0])` */ -export function getCertificateInfo(leafCertBuffer: Buffer): CertificateInfo { +export function getCertificateInfo(leafCertBuffer: Uint8Array): CertificateInfo { const asnx509 = AsnParser.parse(leafCertBuffer, Certificate); const parsedCert = asnx509.tbsCertificate; diff --git a/packages/server/src/helpers/isCertRevoked.ts b/packages/server/src/helpers/isCertRevoked.ts index cc8c3f1..4ea3dda 100644 --- a/packages/server/src/helpers/isCertRevoked.ts +++ b/packages/server/src/helpers/isCertRevoked.ts @@ -4,6 +4,7 @@ import { AsnParser } from '@peculiar/asn1-schema'; import { CertificateList } from '@peculiar/asn1-x509'; import { convertCertBufferToPEM } from './convertCertBufferToPEM'; +import * as uint8Array from './uint8Array'; /** * A cache of revoked cert serial numbers by Authority Key ID @@ -68,7 +69,7 @@ export async function isCertRevoked(cert: X509): Promise<boolean> { return false; } - const data = AsnParser.parse(Buffer.from(crlCert.hex, 'hex'), CertificateList); + const data = AsnParser.parse(uint8Array.fromHex(crlCert.hex), CertificateList); const newCached: CAAuthorityInfo = { revokedCerts: [], @@ -85,7 +86,7 @@ export async function isCertRevoked(cert: X509): Promise<boolean> { if (revokedCerts) { for (const cert of revokedCerts) { - const revokedHex = Buffer.from(cert.userCertificate).toString('hex'); + const revokedHex = uint8Array.toHex(new Uint8Array(cert.userCertificate)); newCached.revokedCerts.push(revokedHex); } diff --git a/packages/server/src/registration/verifications/tpm/parseCertInfo.ts b/packages/server/src/registration/verifications/tpm/parseCertInfo.ts index 6e3d4c3..c590794 100644 --- a/packages/server/src/registration/verifications/tpm/parseCertInfo.ts +++ b/packages/server/src/registration/verifications/tpm/parseCertInfo.ts @@ -1,48 +1,58 @@ import { TPM_ST, TPM_ALG } from './constants'; +import * as uint8Array from '../../../helpers/uint8Array'; /** * Cut up a TPM attestation's certInfo into intelligible chunks */ -export function parseCertInfo(certInfo: Buffer): ParsedCertInfo { +export function parseCertInfo(certInfo: Uint8Array): ParsedCertInfo { let pointer = 0; + const dataView = uint8Array.toDataView(certInfo); // Get a magic constant - const magic = certInfo.slice(pointer, (pointer += 4)).readUInt32BE(0); + const magic = dataView.getUint32(pointer); + pointer += 4; // Determine the algorithm used for attestation - const typeBuffer = certInfo.slice(pointer, (pointer += 2)); - const type = TPM_ST[typeBuffer.readUInt16BE(0)]; + const typeBuffer = dataView.getUint16(pointer); + pointer += 2; + const type = TPM_ST[typeBuffer]; // The name of a parent entity, can be ignored - const qualifiedSignerLength = certInfo.slice(pointer, (pointer += 2)).readUInt16BE(0); + const qualifiedSignerLength = dataView.getUint16(pointer); + pointer += 2; const qualifiedSigner = certInfo.slice(pointer, (pointer += qualifiedSignerLength)); // Get the expected hash of `attsToBeSigned` - const extraDataLength = certInfo.slice(pointer, (pointer += 2)).readUInt16BE(0); + const extraDataLength = dataView.getUint16(pointer); + pointer += 2; const extraData = certInfo.slice(pointer, (pointer += extraDataLength)); // Information about the TPM device's internal clock, can be ignored - const clockInfoBuffer = certInfo.slice(pointer, (pointer += 17)); - const clockInfo = { - clock: clockInfoBuffer.slice(0, 8), - resetCount: clockInfoBuffer.slice(8, 12).readUInt32BE(0), - restartCount: clockInfoBuffer.slice(12, 16).readUInt32BE(0), - safe: !!clockInfoBuffer[16], - }; + const clock = certInfo.slice(pointer, pointer += 8); + const resetCount = dataView.getUint32(pointer); + pointer += 4; + const restartCount = dataView.getUint32(pointer); + pointer += 4; + const safe = !!certInfo.slice(pointer, pointer += 1); + + const clockInfo = { clock, resetCount, restartCount, safe }; // TPM device firmware version const firmwareVersion = certInfo.slice(pointer, (pointer += 8)); // Attested Name - const attestedNameLength = certInfo.slice(pointer, (pointer += 2)).readUInt16BE(0); + const attestedNameLength = dataView.getUint16(pointer); + pointer += 2; const attestedName = certInfo.slice(pointer, (pointer += attestedNameLength)); + const attestedNameDataView = uint8Array.toDataView(attestedName); // Attested qualified name, can be ignored - const qualifiedNameLength = certInfo.slice(pointer, (pointer += 2)).readUInt16BE(0); + const qualifiedNameLength = dataView.getUint16(pointer); + pointer += 2; const qualifiedName = certInfo.slice(pointer, (pointer += qualifiedNameLength)); const attested = { - nameAlg: TPM_ALG[attestedName.slice(0, 2).readUInt16BE(0)], + nameAlg: TPM_ALG[attestedNameDataView.getUint16(0)], nameAlgBuffer: attestedName.slice(0, 2), name: attestedName, qualifiedName, @@ -62,19 +72,19 @@ export function parseCertInfo(certInfo: Buffer): ParsedCertInfo { type ParsedCertInfo = { magic: number; type: string; - qualifiedSigner: Buffer; - extraData: Buffer; + qualifiedSigner: Uint8Array; + extraData: Uint8Array; clockInfo: { - clock: Buffer; + clock: Uint8Array; resetCount: number; restartCount: number; safe: boolean; }; - firmwareVersion: Buffer; + firmwareVersion: Uint8Array; attested: { nameAlg: string; - nameAlgBuffer: Buffer; - name: Buffer; - qualifiedName: Buffer; + nameAlgBuffer: Uint8Array; + name: Uint8Array; + qualifiedName: Uint8Array; }; }; diff --git a/packages/server/src/registration/verifications/tpm/parsePubArea.ts b/packages/server/src/registration/verifications/tpm/parsePubArea.ts index ca61ddc..1476ea4 100644 --- a/packages/server/src/registration/verifications/tpm/parsePubArea.ts +++ b/packages/server/src/registration/verifications/tpm/parsePubArea.ts @@ -1,4 +1,5 @@ import { TPM_ALG, TPM_ECC_CURVE } from './constants'; +import * as uint8Array from '../../../helpers/uint8Array'; /** * Break apart a TPM attestation's pubArea buffer @@ -6,17 +7,20 @@ import { TPM_ALG, TPM_ECC_CURVE } from './constants'; * See 12.2.4 TPMT_PUBLIC here: * https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-00.96-130315.pdf */ -export function parsePubArea(pubArea: Buffer): ParsedPubArea { +export function parsePubArea(pubArea: Uint8Array): ParsedPubArea { let pointer = 0; + const dataView = uint8Array.toDataView(pubArea); - const typeBuffer = pubArea.slice(pointer, (pointer += 2)); - const type = TPM_ALG[typeBuffer.readUInt16BE(0)]; + const type = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; - const nameAlgBuffer = pubArea.slice(pointer, (pointer += 2)); - const nameAlg = TPM_ALG[nameAlgBuffer.readUInt16BE(0)]; + const nameAlg = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; // Get some authenticator attributes(?) - const objectAttributesInt = pubArea.slice(pointer, (pointer += 4)).readUInt32BE(0); + // const objectAttributesInt = pubArea.slice(pointer, (pointer += 4)).readUInt32BE(0); + const objectAttributesInt = dataView.getUint32(pointer); + pointer += 4; const objectAttributes = { fixedTPM: !!(objectAttributesInt & 1), stClear: !!(objectAttributesInt & 2), @@ -32,52 +36,70 @@ export function parsePubArea(pubArea: Buffer): ParsedPubArea { }; // Slice out the authPolicy of dynamic length - const authPolicyLength = pubArea.slice(pointer, (pointer += 2)).readUInt16BE(0); + const authPolicyLength = dataView.getUint16(pointer); + pointer += 2; const authPolicy = pubArea.slice(pointer, (pointer += authPolicyLength)); // Extract additional curve params according to type const parameters: { rsa?: RSAParameters; ecc?: ECCParameters } = {}; - let unique = Buffer.from([]); + let unique = Uint8Array.from([]); if (type === 'TPM_ALG_RSA') { - const rsaBuffer = pubArea.slice(pointer, (pointer += 10)); + const symmetric = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; - parameters.rsa = { - symmetric: TPM_ALG[rsaBuffer.slice(0, 2).readUInt16BE(0)], - scheme: TPM_ALG[rsaBuffer.slice(2, 4).readUInt16BE(0)], - keyBits: rsaBuffer.slice(4, 6).readUInt16BE(0), - exponent: rsaBuffer.slice(6, 10).readUInt32BE(0), - }; + const scheme = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; + + const keyBits = dataView.getUint16(pointer); + pointer += 2; + + const exponent = dataView.getUint32(pointer); + pointer += 4; + + parameters.rsa = { symmetric, scheme, keyBits, exponent }; /** * See 11.2.4.5 TPM2B_PUBLIC_KEY_RSA here: * https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-00.96-130315.pdf */ - const uniqueLength = pubArea.slice(pointer, (pointer += 2)).readUInt16BE(0); + // const uniqueLength = pubArea.slice(pointer, (pointer += 2)).readUInt16BE(0); + const uniqueLength = dataView.getUint16(pointer); + pointer += 2; unique = pubArea.slice(pointer, (pointer += uniqueLength)); } else if (type === 'TPM_ALG_ECC') { - const eccBuffer = pubArea.slice(pointer, (pointer += 8)); + const symmetric = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; + + const scheme = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; + + const curveID = TPM_ECC_CURVE[dataView.getUint16(pointer)]; + pointer += 2; - parameters.ecc = { - symmetric: TPM_ALG[eccBuffer.slice(0, 2).readUInt16BE(0)], - scheme: TPM_ALG[eccBuffer.slice(2, 4).readUInt16BE(0)], - curveID: TPM_ECC_CURVE[eccBuffer.slice(4, 6).readUInt16BE(0)], - kdf: TPM_ALG[eccBuffer.slice(6, 8).readUInt16BE(0)], - }; + const kdf = TPM_ALG[dataView.getUint16(pointer)]; + pointer += 2; + + parameters.ecc = { symmetric, scheme, curveID, kdf }; /** * See 11.2.5.1 TPM2B_ECC_PARAMETER here: * https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-00.96-130315.pdf */ // Retrieve X - const uniqueXLength = pubArea.slice(pointer, (pointer += 2)).readUInt16BE(0); + const uniqueXLength = dataView.getUint16(pointer); + pointer += 2; + const uniqueX = pubArea.slice(pointer, (pointer += uniqueXLength)); + // Retrieve Y - const uniqueYLength = pubArea.slice(pointer, (pointer += 2)).readUInt16BE(0); + const uniqueYLength = dataView.getUint16(pointer); + pointer += 2; + const uniqueY = pubArea.slice(pointer, (pointer += uniqueYLength)); - unique = Buffer.concat([uniqueX, uniqueY]); + unique = uint8Array.concat([uniqueX, uniqueY]); } else { throw new Error(`Unexpected type "${type}" (TPM)`); } @@ -108,12 +130,12 @@ type ParsedPubArea = { decrypt: boolean; signOrEncrypt: boolean; }; - authPolicy: Buffer; + authPolicy: Uint8Array; parameters: { rsa?: RSAParameters; ecc?: ECCParameters; }; - unique: Buffer; + unique: Uint8Array; }; type RSAParameters = { diff --git a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts index 910e8f3..c1c4306 100644 --- a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts +++ b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts @@ -74,7 +74,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt throw new Error('COSE public key missing e (TPM|RSA)'); } - if (!unique.equals(n as Buffer)) { + if (!uint8Array.areEqual(unique, (n as Buffer))) { throw new Error('PubArea unique is not same as credentialPublicKey (TPM|RSA)'); } @@ -107,7 +107,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt throw new Error('COSE public key missing y (TPM|ECC)'); } - if (!unique.equals(Buffer.concat([x as Buffer, y as Buffer]))) { + if (!uint8Array.areEqual(unique, uint8Array.concat([x as Uint8Array, y as Uint8Array]))) { throw new Error('PubArea unique is not same as public key x and y (TPM|ECC)'); } @@ -141,22 +141,22 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt const pubAreaHash = toHash(pubArea, attested.nameAlg.replace('TPM_ALG_', '')); // Concatenate attested.nameAlg and pubAreaHash to create attestedName. - const attestedName = Buffer.concat([attested.nameAlgBuffer, pubAreaHash]); + const attestedName = uint8Array.concat([attested.nameAlgBuffer, pubAreaHash]); // Check that certInfo.attested.name is equals to attestedName. - if (!attested.name.equals(attestedName)) { + if (!uint8Array.areEqual(attested.name, attestedName)) { throw new Error(`Attested name comparison failed (TPM)`); } // Concatenate authData with clientDataHash to create attToBeSigned - const attToBeSigned = Buffer.concat([authData, clientDataHash]); + const attToBeSigned = uint8Array.concat([authData, clientDataHash]); // Hash attToBeSigned using the algorithm specified in attStmt.alg to create attToBeSignedHash const hashAlg: string = COSEALGHASH[alg as number]; const attToBeSignedHash = toHash(attToBeSigned, hashAlg); // Check that certInfo.extraData is equals to attToBeSignedHash. - if (!extraData.equals(attToBeSignedHash)) { + if (!uint8Array.areEqual(extraData, attToBeSignedHash)) { throw new Error('CertInfo extra data did not equal hashed attestation (TPM)'); } diff --git a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts index ed0bb61..27bef78 100644 --- a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts +++ b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts @@ -62,7 +62,7 @@ export async function verifyAttestationAndroidKey( // Verify extKeyStore values const { attestationChallenge, teeEnforced, softwareEnforced } = parsedExtKeyStore; - if (!Buffer.from(attestationChallenge.buffer).equals(clientDataHash)) { + if (!uint8Array.areEqual(new Uint8Array(attestationChallenge.buffer), clientDataHash)) { throw new Error('Attestation challenge was not equal to client data hash (AndroidKey)'); } @@ -99,7 +99,7 @@ export async function verifyAttestationAndroidKey( } } - const signatureBase = Buffer.concat([authData, clientDataHash]); + const signatureBase = uint8Array.concat([authData, clientDataHash]); const hashAlg = COSEALGHASH[alg as number]; return verifySignature({ diff --git a/packages/server/src/registration/verifications/verifyAttestationApple.ts b/packages/server/src/registration/verifications/verifyAttestationApple.ts index a54c465..928f6c6 100644 --- a/packages/server/src/registration/verifications/verifyAttestationApple.ts +++ b/packages/server/src/registration/verifications/verifyAttestationApple.ts @@ -45,7 +45,7 @@ export async function verifyAttestationApple( throw new Error('credCert missing "1.2.840.113635.100.8.2" extension (Apple)'); } - const nonceToHash = Buffer.concat([authData, clientDataHash]); + const nonceToHash = uint8Array.concat([authData, clientDataHash]); const nonce = toHash(nonceToHash, 'SHA256'); /** * Ignore the first six ASN.1 structure bytes that define the nonce as an OCTET STRING. Should @@ -54,7 +54,7 @@ export async function verifyAttestationApple( * TODO: Try and get @peculiar (GitHub) to add a schema for "1.2.840.113635.100.8.2" when we * find out where it's defined (doesn't seem to be publicly documented at the moment...) */ - const extNonce = Buffer.from(extCertNonce.extnValue.buffer).slice(6); + const extNonce = new Uint8Array(extCertNonce.extnValue.buffer).slice(6); if (!uint8Array.areEqual(nonce, extNonce)) { throw new Error(`credCert nonce was not expected value (Apple)`); @@ -64,7 +64,7 @@ export async function verifyAttestationApple( * Verify credential public key matches the Subject Public Key of credCert */ const credPubKeyPKCS = convertCOSEtoPKCS(credentialPublicKey); - const credCertSubjectPublicKey = Buffer.from(subjectPublicKeyInfo.subjectPublicKey); + const credCertSubjectPublicKey = new Uint8Array(subjectPublicKeyInfo.subjectPublicKey); if (!uint8Array.areEqual(credPubKeyPKCS, credCertSubjectPublicKey)) { throw new Error('Credential public key does not equal credCert public key (Apple)'); diff --git a/packages/server/src/registration/verifications/verifyAttestationFIDOU2F.ts b/packages/server/src/registration/verifications/verifyAttestationFIDOU2F.ts index ea705d0..591149f 100644 --- a/packages/server/src/registration/verifications/verifyAttestationFIDOU2F.ts +++ b/packages/server/src/registration/verifications/verifyAttestationFIDOU2F.ts @@ -22,10 +22,10 @@ export async function verifyAttestationFIDOU2F( rootCertificates, } = options; - const reservedByte = Buffer.from([0x00]); + const reservedByte = Uint8Array.from([0x00]); const publicKey = convertCOSEtoPKCS(credentialPublicKey); - const signatureBase = Buffer.concat([ + const signatureBase = uint8Array.concat([ reservedByte, rpIdHash, clientDataHash, diff --git a/packages/server/src/registration/verifications/verifyAttestationPacked.ts b/packages/server/src/registration/verifications/verifyAttestationPacked.ts index 02beebc..aa2d4b9 100644 --- a/packages/server/src/registration/verifications/verifyAttestationPacked.ts +++ b/packages/server/src/registration/verifications/verifyAttestationPacked.ts @@ -27,7 +27,7 @@ export async function verifyAttestationPacked( throw new Error(`Attestation Statement alg "${alg}" is not a number (Packed)`); } - const signatureBase = Buffer.concat([authData, clientDataHash]); + const signatureBase = uint8Array.concat([authData, clientDataHash]); let verified = false; diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts index 87deb85..1711108 100644 --- a/packages/server/src/registration/verifyRegistrationResponse.ts +++ b/packages/server/src/registration/verifyRegistrationResponse.ts @@ -141,14 +141,14 @@ export async function verifyRegistrationResponse( // Make sure the response's RP ID is ours if (expectedRPID) { if (typeof expectedRPID === 'string') { - const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii')); + const expectedRPIDHash = toHash(uint8Array.fromASCIIString(expectedRPID)); if (!uint8Array.areEqual(rpIdHash, expectedRPIDHash)) { throw new Error(`Unexpected RP ID hash`); } } else { // Go through each expected RP ID and try to find one that matches const foundMatch = expectedRPID.some(expected => { - const expectedRPIDHash = toHash(Buffer.from(expected, 'ascii')); + const expectedRPIDHash = toHash(uint8Array.fromASCIIString(expected)); return uint8Array.areEqual(rpIdHash, expectedRPIDHash); }); |