diff options
author | Matthew Miller <matthew@millerti.me> | 2022-11-19 22:22:33 -0800 |
---|---|---|
committer | Matthew Miller <matthew@millerti.me> | 2022-11-19 22:22:33 -0800 |
commit | 52e1abca516295c2f0cf34353ed5c5c01d77d3c7 (patch) | |
tree | 89a40a80cbdc3e9810b184a9b7d3333df50c856e /packages/server/src | |
parent | a7f2514c381e5f57f27dfaf887a633045747eb4f (diff) |
Streamline calls to verifySignature()
Diffstat (limited to 'packages/server/src')
4 files changed, 12 insertions, 160 deletions
diff --git a/packages/server/src/helpers/verifySignature.ts b/packages/server/src/helpers/verifySignature.ts index 19cbac1..ff4e73b 100644 --- a/packages/server/src/helpers/verifySignature.ts +++ b/packages/server/src/helpers/verifySignature.ts @@ -1,13 +1,7 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { verify as ed25519Verify } from '@noble/ed25519'; -import { AsnParser } from '@peculiar/asn1-schema'; -import { Certificate } from '@peculiar/asn1-x509'; -import { ECParameters, id_ecPublicKey, id_secp256r1 } from '@peculiar/asn1-ecc'; -import { RSAPublicKey } from '@peculiar/asn1-rsa'; - -import { COSEALG, COSECRV, COSEKEYS, COSEKTY, COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyRSA, isCOSEAlg, isCOSEPublicKeyOKP } from './convertCOSEtoPKCS'; +import { COSEALG, COSEPublicKey } from './cose'; import { isoCrypto } from './iso'; import { decodeCredentialPublicKey } from './decodeCredentialPublicKey'; +import { convertX509PublicKeyToCOSE } from './convertX509PublicKeyToCOSE'; /** * Verify an authenticator's signature @@ -17,9 +11,9 @@ export async function verifySignature(opts: { data: Uint8Array; credentialPublicKey?: Uint8Array; leafCertificate?: Uint8Array; - rsaHashAlgorithm?: string; + attestationHashAlgorithm?: COSEALG; }): Promise<boolean> { - const { signature, data, credentialPublicKey, leafCertificate, rsaHashAlgorithm } = opts; + const { signature, data, credentialPublicKey, leafCertificate, attestationHashAlgorithm } = opts; if (!leafCertificate && !credentialPublicKey) { throw new Error('Must declare either "leafCert" or "credentialPublicKey"'); @@ -29,156 +23,18 @@ export async function verifySignature(opts: { throw new Error('Must not declare both "leafCert" and "credentialPublicKey"'); } - let subtlePublicKey: CryptoKey; - let kty: COSEKTY; - let alg: COSEALG; + let cosePublicKey: COSEPublicKey = new Map(); if (credentialPublicKey) { - const cosePublicKey = decodeCredentialPublicKey(credentialPublicKey); - - const _kty = cosePublicKey.get(COSEKEYS.kty); - const _alg = cosePublicKey.get(COSEKEYS.alg); - - if (!_kty) { - throw new Error('Public key was missing kty'); - } - - if (!_alg) { - throw new Error('Public key was missing alg'); - } - - if (!isCOSEAlg(_alg)) { - throw new Error(`Public key contained invalid alg ${_alg}`); - } - - // Verify Ed25519 slightly differently - if (isCOSEPublicKeyOKP(cosePublicKey)) { - const x = cosePublicKey.get(COSEKEYS.x); - - if (!x) { - throw new Error('Public key was missing x (OKP)'); - } - - return ed25519Verify(signature, data, x); - } - - // Assume we're handling COSEKTY.EC2 or COSEKTY.RSA key from here on - subtlePublicKey = await isoCrypto.importKey(cosePublicKey as COSEPublicKeyEC2 | COSEPublicKeyRSA); - kty = _kty as COSEKTY; - alg = _alg; + cosePublicKey = decodeCredentialPublicKey(credentialPublicKey); } else if (leafCertificate) { - /** - * Time to extract the public key from an X.509 leaf certificate - */ - const x509 = AsnParser.parse(leafCertificate, Certificate); - - const { tbsCertificate } = x509; - const { - subjectPublicKeyInfo, - signature: _tbsSignature, - } = tbsCertificate; - - // console.log(tbsCertificate); - - const signatureAlgorithm = _tbsSignature.algorithm; - const publicKeyAlgorithmID = subjectPublicKeyInfo.algorithm.algorithm; - - if (publicKeyAlgorithmID === id_ecPublicKey) { - /** - * EC2 Public Key - */ - kty = COSEKTY.EC2; - - if (!subjectPublicKeyInfo.algorithm.parameters) { - throw new Error('Leaf cert public key missing parameters (EC2)'); - } - - const ecParameters = AsnParser.parse(new Uint8Array(subjectPublicKeyInfo.algorithm.parameters), ECParameters); - - let crv = -999; - if (ecParameters.namedCurve === id_secp256r1) { - crv = COSECRV.P256; - } else { - throw new Error( - `Leaf cert public key contained unexpected namedCurve ${ecParameters.namedCurve} (EC2)`, - ); - } - - const subjectPublicKey = new Uint8Array(subjectPublicKeyInfo.subjectPublicKey) - - let x: Uint8Array; - let y: Uint8Array; - if (subjectPublicKey[0] === 0x04) { - // Public key is in "uncompressed form", so we can split the remaining bytes in half - let pointer = 1; - const halfLength = (subjectPublicKey.length - 1) / 2; - x = subjectPublicKey.slice(pointer, pointer += halfLength); - y = subjectPublicKey.slice(pointer); - } else { - throw new Error('TODO: Figure out how to handle public keys in "compressed form"'); - } - - const coseEC2PubKey: COSEPublicKeyEC2 = new Map(); - coseEC2PubKey.set(COSEKEYS.kty, COSEKTY.EC2); - coseEC2PubKey.set(COSEKEYS.crv, crv); - coseEC2PubKey.set(COSEKEYS.x, x); - coseEC2PubKey.set(COSEKEYS.y, y); - - subtlePublicKey = await isoCrypto.importKey(coseEC2PubKey); - alg = -7; - } else if (publicKeyAlgorithmID === '1.2.840.113549.1.1.1') { - /** - * RSA public key - */ - kty = COSEKTY.RSA; - const rsaPublicKey = AsnParser.parse(subjectPublicKeyInfo.subjectPublicKey, RSAPublicKey); - - let _alg: COSEALG; - if (signatureAlgorithm === '1.2.840.113549.1.1.11') { - _alg = -257; // RS256 - } else if (signatureAlgorithm === '1.2.840.113549.1.1.12') { - _alg = -258; // RS384 - } else if (signatureAlgorithm === '1.2.840.113549.1.1.13') { - _alg = -259; // RS512 - } else { - throw new Error( - `Leaf cert contained unexpected signature algorithm ${signatureAlgorithm} (RSA)`, - ); - } - - const coseRSAPubKey: COSEPublicKeyRSA = new Map(); - coseRSAPubKey.set(COSEKEYS.kty, COSEKTY.RSA); - coseRSAPubKey.set(COSEKEYS.alg, _alg); - coseRSAPubKey.set(COSEKEYS.n, new Uint8Array(rsaPublicKey.modulus)); - coseRSAPubKey.set(COSEKEYS.e, new Uint8Array(rsaPublicKey.publicExponent)); - - subtlePublicKey = await isoCrypto.importKey(coseRSAPubKey, rsaHashAlgorithm); - alg = _alg; - } else { - throw new Error(`Unexpected leaf cert public key algorithm ${publicKeyAlgorithmID}`); - } - } else { - throw new Error( - 'How did we get here? We were supposed to make sure we were only dealing with one of two possible sets of method arguments!!', - ); - } - - if ( - // @ts-ignore 2454 - typeof subtlePublicKey === 'undefined' - // @ts-ignore 2454 - || typeof kty === 'undefined' - // @ts-ignore 2454 - || typeof alg === 'undefined' - ) { - throw new Error('You must import a public key, and determine kty and alg before proceeding'); + cosePublicKey = convertX509PublicKeyToCOSE(leafCertificate); } return isoCrypto.verify({ - publicKey: subtlePublicKey, - coseKty: kty, - coseAlg: alg, + cosePublicKey, signature, data, + shaHashOverride: attestationHashAlgorithm, }); } diff --git a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts index 18c9abd..5a10322 100644 --- a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts +++ b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts @@ -174,7 +174,6 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt const attToBeSigned = isoUint8Array.concat([authData, clientDataHash]); // Hash attToBeSigned using the algorithm specified in attStmt.alg to create attToBeSignedHash - const hashAlg: string = coseAlgSHAHashMap[alg]; const attToBeSignedHash = await toHash(attToBeSigned, alg); // Check that certInfo.extraData is equals to attToBeSignedHash. @@ -305,7 +304,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt signature: sig, data: certInfo, leafCertificate: x5c[0], - rsaHashAlgorithm: hashAlg + attestationHashAlgorithm: alg, }); } diff --git a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts index cceedb8..1f3eb83 100644 --- a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts +++ b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts @@ -107,12 +107,11 @@ export async function verifyAttestationAndroidKey( } const signatureBase = isoUint8Array.concat([authData, clientDataHash]); - const hashAlg = coseAlgSHAHashMap[alg]; return verifySignature({ signature: sig, data: signatureBase, leafCertificate: x5c[0], - rsaHashAlgorithm: hashAlg + attestationHashAlgorithm: alg, }); } diff --git a/packages/server/src/registration/verifications/verifyAttestationPacked.ts b/packages/server/src/registration/verifications/verifyAttestationPacked.ts index a03f22b..0fc84b8 100644 --- a/packages/server/src/registration/verifications/verifyAttestationPacked.ts +++ b/packages/server/src/registration/verifications/verifyAttestationPacked.ts @@ -118,13 +118,11 @@ export async function verifyAttestationPacked( leafCertificate: x5c[0], }); } else { - const hashAlg: string = coseAlgSHAHashMap[alg]; - verified = await verifySignature({ signature: sig, data: signatureBase, credentialPublicKey, - rsaHashAlgorithm: hashAlg + attestationHashAlgorithm: alg }); } |