diff options
7 files changed, 37 insertions, 94 deletions
diff --git a/packages/server/src/assertion/verifyAssertionResponse.ts b/packages/server/src/assertion/verifyAssertionResponse.ts index c126b84..fb668f4 100644 --- a/packages/server/src/assertion/verifyAssertionResponse.ts +++ b/packages/server/src/assertion/verifyAssertionResponse.ts @@ -27,28 +27,20 @@ export default function verifyAssertionResponse( const { base64AuthenticatorData, base64ClientDataJSON, base64Signature } = response; const clientDataJSON = decodeClientDataJSON(base64ClientDataJSON); - console.debug('decodedClientDataJSON:', clientDataJSON); - const { type, origin } = clientDataJSON; // Check that the origin is our site if (origin !== expectedOrigin) { - console.error('client origin did not equal our origin'); - console.debug('expectedOrigin:', expectedOrigin); - console.debug('assertion\'s origin:', origin); - throw new Error('Assertion origin was an unexpected value'); + throw new Error(`Unexpected assertion origin: ${origin}`); } // Make sure we're handling an assertion if (type !== 'webauthn.get') { - console.error('type did not equal "webauthn.get"'); - console.debug('attestation\'s type:', type); - throw new Error('Assertion type was an unexpected value'); + throw new Error(`Unexpected assertion type: ${type}`); } const authDataBuffer = base64url.toBuffer(base64AuthenticatorData); const authData = parseAssertionAuthData(authDataBuffer); - console.log('parsed authData:', authData); if (!(authData.flags & U2F_USER_PRESENTED)) { throw new Error('User was NOT present during assertion!'); @@ -66,8 +58,9 @@ export default function verifyAssertionResponse( // dataStruct. It's related to how the authenticator maintains the number of times its been // used for this client. If this happens, then someone's somehow increased the counter // on the device without going through this site - console.debug(`Response counter ${counter} was not greater than ${authenticator.counter}`); - throw new Error(`Counter in response did not increment from ${authenticator.counter}`); + throw new Error( + `Response counter value ${counter} was lower than expected ${authenticator.counter}`, + ); } const clientDataHash = toHash(base64url.toBuffer(base64ClientDataJSON)); diff --git a/packages/server/src/attestation/parseAttestationAuthData.ts b/packages/server/src/attestation/parseAttestationAuthData.ts index 8326c85..b51af5f 100644 --- a/packages/server/src/attestation/parseAttestationAuthData.ts +++ b/packages/server/src/attestation/parseAttestationAuthData.ts @@ -4,8 +4,6 @@ import { ParsedAttestationAuthData } from "@webauthntine/typescript-types"; * Make sense of the authData buffer contained in an Attestation */ export default function parseAttestationAuthData(authData: Buffer): ParsedAttestationAuthData { - console.log('parsing attestation auth data'); - let intBuffer = authData; const rpIdHash = intBuffer.slice(0, 32); @@ -24,8 +22,6 @@ export default function parseAttestationAuthData(authData: Buffer): ParsedAttest flagsInt, }; - console.debug('flags:', flags); - const counterBuf = intBuffer.slice(0, 4); intBuffer = intBuffer.slice(4); diff --git a/packages/server/src/attestation/verifications/verifyAndroidSafetyNet.ts b/packages/server/src/attestation/verifications/verifyAndroidSafetyNet.ts index 0f92613..6f5365a 100644 --- a/packages/server/src/attestation/verifications/verifyAndroidSafetyNet.ts +++ b/packages/server/src/attestation/verifications/verifyAndroidSafetyNet.ts @@ -25,7 +25,7 @@ export default function verifyAttestationAndroidSafetyNet( const { attStmt, authData, fmt } = attestationObject; if (!attStmt.response) { - throw new Error('No response was included in attStmt by authenticator'); + throw new Error('No response was included in attStmt by authenticator (SafetyNet)'); } // Prepare to verify a JWT @@ -36,10 +36,6 @@ export default function verifyAttestationAndroidSafetyNet( const PAYLOAD: SafetyNetJWTPayload = JSON.parse(base64url.decode(jwtParts[1])); const SIGNATURE: SafetyNetJWTSignature = jwtParts[2]; - console.debug('HEADER:', HEADER); - console.debug('PAYLOAD:', PAYLOAD); - console.debug('SIGNATURE:', SIGNATURE); - /** * START Verify PAYLOAD */ @@ -54,16 +50,11 @@ export default function verifyAttestationAndroidSafetyNet( const expectedNonce = nonceBuffer.toString('base64'); if (nonce !== expectedNonce) { - console.error('Payload nonce was not the expected value!'); - console.debug('payload nonce:', PAYLOAD.nonce); - console.debug('expected nonce:', expectedNonce); - throw new Error('Could not verify response payload nonce'); + throw new Error('Could not verify payload nonce (SafetyNet)'); } if (!ctsProfileMatch) { - console.error('ctsProfileMatch was false!'); - console.debug('ctsProfileMatch:', ctsProfileMatch); - throw new Error('Could not verify response payload profile'); + throw new Error('Could not verify device integrity (SafetyNet)'); } /** * END Verify PAYLOAD @@ -83,19 +74,15 @@ export default function verifyAttestationAndroidSafetyNet( return `-----BEGIN CERTIFICATE-----\n${pem}-----END CERTIFICATE-----`; }); - console.debug('fullpathCert:', fullpathCert); - const certificate = fullpathCert[0]; const commonCertInfo = getCertificateInfo(certificate); - console.debug('commonCertInfo:', commonCertInfo); const { subject } = commonCertInfo; // TODO: Find out where this CN string is specified and if it might change if (subject.CN !== 'attest.android.com') { - console.error('common name was not "attest.android.com"'); - throw new Error('Could not verify certificate common name'); + throw new Error('Certificate common name was not "attest.android.com" (SafetyNet)'); } // TODO: Re-investigate this if we decide to "use MDS or Metadata Statements" @@ -121,17 +108,16 @@ export default function verifyAttestationAndroidSafetyNet( if (toReturn.verified) { const authDataStruct = parseAttestationAuthData(authData); - console.debug('authDataStruct:', authDataStruct); const { counter, credentialID, COSEPublicKey, flags } = authDataStruct; toReturn.userVerified = flags.uv; if (!COSEPublicKey) { - throw new Error('No public key was provided by authenticator'); + throw new Error('No public key was provided by authenticator (SafetyNet)'); } if (!credentialID) { - throw new Error('No credential ID was provided by authenticator'); + throw new Error('No credential ID was provided by authenticator (SafetyNet)'); } const publicKey = convertCOSEtoPKCS(COSEPublicKey); diff --git a/packages/server/src/attestation/verifications/verifyFIDOU2F.ts b/packages/server/src/attestation/verifications/verifyFIDOU2F.ts index b60597d..75e664f 100644 --- a/packages/server/src/attestation/verifications/verifyFIDOU2F.ts +++ b/packages/server/src/attestation/verifications/verifyFIDOU2F.ts @@ -28,15 +28,15 @@ export default function verifyAttestationFIDOU2F( } = authDataStruct; if (!(flags.flagsInt & U2F_USER_PRESENTED)) { - throw new Error('User was NOT present during authentication'); + throw new Error('User was NOT present during authentication (FIDOU2F)'); } if (!COSEPublicKey) { - throw new Error('No public key was provided by authenticator'); + throw new Error('No public key was provided by authenticator (FIDOU2F)'); } if (!credentialID) { - throw new Error('No credential ID was provided by authenticator'); + throw new Error('No credential ID was provided by authenticator (FIDOU2F)'); } const clientDataHash = toHash(base64url.toBuffer(base64ClientDataJSON)); @@ -54,11 +54,11 @@ export default function verifyAttestationFIDOU2F( const { sig, x5c } = attStmt; if (!x5c) { - throw new Error('No attestation certificate provided in attestation statement'); + throw new Error('No attestation certificate provided in attestation statement (FIDOU2F)'); } if (!sig) { - throw new Error('No attestation signature provided in attestation statement'); + throw new Error('No attestation signature provided in attestation statement (FIDOU2F)'); } const publicKeyCertPEM = convertASN1toPEM(x5c[0]); diff --git a/packages/server/src/attestation/verifications/verifyNone.ts b/packages/server/src/attestation/verifications/verifyNone.ts index a6b742a..4f967d1 100644 --- a/packages/server/src/attestation/verifications/verifyNone.ts +++ b/packages/server/src/attestation/verifications/verifyNone.ts @@ -17,8 +17,6 @@ export default function verifyAttestationNone( const { fmt, authData } = attestationObject; const authDataStruct = parseAttestationAuthData(authData); - console.log('authDataStruct:', authDataStruct); - const { credentialID, COSEPublicKey, @@ -27,22 +25,16 @@ export default function verifyAttestationNone( } = authDataStruct; if (!COSEPublicKey) { - throw new Error('No public key was provided by authenticator'); + throw new Error('No public key was provided by authenticator (None)'); } if (!credentialID) { - throw new Error('No credential ID was provided by authenticator'); + throw new Error('No credential ID was provided by authenticator (None)'); } // Make sure the (U)ser (P)resent for the attestation if (!flags.up) { - console.error('User was not Present for attestation'); - console.debug('attestation\'s flags:', flags); - throw new Error('User presence could not be verified'); - } - - if (!flags.uv) { - console.warn('The authenticator could not uniquely Verify the user'); + throw new Error('User was not present for attestation (None)'); } const publicKey = convertCOSEtoPKCS(COSEPublicKey); diff --git a/packages/server/src/attestation/verifications/verifyPacked.ts b/packages/server/src/attestation/verifications/verifyPacked.ts index 04aff7b..18e195f 100644 --- a/packages/server/src/attestation/verifications/verifyPacked.ts +++ b/packages/server/src/attestation/verifications/verifyPacked.ts @@ -27,15 +27,15 @@ export default function verifyAttestationPacked(attestationObject: AttestationOb const { COSEPublicKey, counter, credentialID, flags } = authDataStruct; if (!COSEPublicKey) { - throw new Error('No public key was provided by authenticator'); + throw new Error('No public key was provided by authenticator (Packed)'); } if (!credentialID) { - throw new Error('No credential ID was provided by authenticator'); + throw new Error('No credential ID was provided by authenticator (Packed)'); } if (!sig) { - throw new Error('No attestation signature provided in attestation statement'); + throw new Error('No attestation signature provided in attestation statement (Packed)'); } const clientDataHash = toHash(base64url.toBuffer(base64ClientDataJSON)); @@ -52,8 +52,6 @@ export default function verifyAttestationPacked(attestationObject: AttestationOb const publicKey = convertCOSEtoPKCS(COSEPublicKey); if (x5c) { - console.log('FULL Attestation'); - const leafCert = convertASN1toPEM(x5c[0]); const leafCertInfo = getCertificateInfo(leafCert); @@ -66,57 +64,53 @@ export default function verifyAttestationPacked(attestationObject: AttestationOb } = subject; if (OU !== 'Authenticator Attestation') { - throw new Error('Batch certificate OU MUST be set strictly to "Authenticator Attestation"!'); + throw new Error('Batch certificate OU MUST be set strictly to "Authenticator Attestation"! (Packed|Full'); } if (!CN) { - throw new Error('Batch certificate CN MUST no be empty!'); + throw new Error('Batch certificate CN MUST no be empty! (Packed|Full'); } if (!O) { - throw new Error('Batch certificate CN MUST no be empty!'); + throw new Error('Batch certificate CN MUST no be empty! (Packed|Full'); } if (!C || C.length !== 2) { - throw new Error('Batch certificate C MUST be set to two character ISO 3166 code!'); + throw new Error('Batch certificate C MUST be set to two character ISO 3166 code! (Packed|Full'); } if (basicConstraintsCA) { - throw new Error('Batch certificate basic constraints CA MUST be false!'); + throw new Error('Batch certificate basic constraints CA MUST be false! (Packed|Full'); } if (version !== 3) { - throw new Error('Batch certificate version MUST be 3(ASN1 2)!'); + throw new Error('Batch certificate version MUST be 3(ASN1 2)! (Packed|Full'); } toReturn.verified = verifySignature(sig, signatureBase, leafCert); } else if (ecdaaKeyId) { - throw new Error('ECDAA not supported yet'); + throw new Error('ECDAA not supported yet (Packed|ECDAA)'); } else { - console.log('SELF Attestation'); - const cosePublicKey: COSEPublicKey = cbor.decodeAllSync(COSEPublicKey)[0]; const kty = cosePublicKey.get(COSEKEYS.kty); const alg = cosePublicKey.get(COSEKEYS.alg); if (!alg) { - throw new Error('COSE public key was missing alg'); + throw new Error('COSE public key was missing alg (Packed|Self)'); } if (!kty) { - throw new Error('COSE public key was missing kty'); + throw new Error('COSE public key was missing kty (Packed|Self)'); } const hashAlg: string = COSEALGHASH[(alg as number)]; if (kty === COSEKTY.EC2) { - console.log('EC2'); - const crv = cosePublicKey.get(COSEKEYS.crv); if (!crv) { - throw new Error('COSE public key was missing kty crv'); + throw new Error('COSE public key was missing kty crv (Packed|EC2)'); } const pkcsPublicKey = convertCOSEtoPKCS(cosePublicKey); @@ -127,12 +121,10 @@ export default function verifyAttestationPacked(attestationObject: AttestationOb toReturn.verified = key.verify(signatureBaseHash, sig); } else if (kty === COSEKTY.RSA) { - console.log('RSA'); - const n = cosePublicKey.get(COSEKEYS.n); if (!n) { - throw new Error('COSE public key was missing n'); + throw new Error('COSE public key was missing n (Packed|RSA)'); } const signingScheme = COSERSASCHEME[alg as number]; @@ -147,12 +139,10 @@ export default function verifyAttestationPacked(attestationObject: AttestationOb toReturn.verified = key.verify(signatureBase, sig); } else if (kty === COSEKTY.OKP) { - console.log('OKP'); - const x = cosePublicKey.get(COSEKEYS.x); if (!x) { - throw new Error('COSE public key was missing x'); + throw new Error('COSE public key was missing x (Packed|OKP)'); } const signatureBaseHash = toHash(signatureBase, hashAlg); diff --git a/packages/server/src/attestation/verifyAttestationResponse.ts b/packages/server/src/attestation/verifyAttestationResponse.ts index 9b90391..f302771 100644 --- a/packages/server/src/attestation/verifyAttestationResponse.ts +++ b/packages/server/src/attestation/verifyAttestationResponse.ts @@ -21,24 +21,16 @@ export default function verifyAttestationResponse( const attestationObject = decodeAttestationObject(base64AttestationObject); const clientDataJSON = decodeClientDataJSON(base64ClientDataJSON); - console.debug('decoded attestationObject:', attestationObject); - console.debug('decoded clientDataJSON:', clientDataJSON); - const { type, origin } = clientDataJSON; // Check that the origin is our site if (origin !== expectedOrigin) { - console.error('client origin did not equal our origin'); - console.debug('Expected Origin:', expectedOrigin); - console.debug('attestation\'s origin:', origin); - throw new Error('Attestation origin was an unexpected value'); + throw new Error(`Unexpected attestation origin: ${origin}`); } // Make sure we're handling an attestation if (type !== 'webauthn.create') { - console.error('type did not equal "webauthn.create"'); - console.debug('attestation\'s type:', type); - throw new Error('Attestation type was an unexpected value'); + throw new Error(`Unexpected attestation type: ${type}`); } const { fmt } = attestationObject; @@ -47,26 +39,20 @@ export default function verifyAttestationResponse( * Verification can only be performed when attestation = 'direct' */ if (fmt === ATTESTATION_FORMATS.FIDO_U2F) { - console.log('Decoding FIDO-U2F attestation'); return verifyFIDOU2F(attestationObject, base64ClientDataJSON); } if (fmt === ATTESTATION_FORMATS.PACKED) { - console.log('Decoding Packed attestation'); return verifyPacked(attestationObject, base64ClientDataJSON); } if (fmt === ATTESTATION_FORMATS.ANDROID_SAFETYNET) { - console.log('Decoding Android Safetynet attestation'); return verifyAndroidSafetynet(attestationObject, base64ClientDataJSON); } if (fmt === ATTESTATION_FORMATS.NONE) { - console.log('Decoding None attestation'); return verifyNone(attestationObject); } - const reason = `Unsupported Attestation Format: ${fmt}`; - console.error(reason); - throw new Error(reason); + throw new Error(`Unsupported Attestation Format: ${fmt}`); } |