@simplewebauthn/server
Advanced tools
Comparing version 5.1.0 to 5.2.0
@@ -22,3 +22,3 @@ "use strict"; | ||
function generateAuthenticationOptions(options = {}) { | ||
const { allowCredentials, challenge = generateChallenge_1.default(), timeout = 60000, userVerification, extensions, rpID, } = options; | ||
const { allowCredentials, challenge = (0, generateChallenge_1.default)(), timeout = 60000, userVerification, extensions, rpID, } = options; | ||
return { | ||
@@ -25,0 +25,0 @@ challenge: base64url_1.default.encode(challenge), |
/// <reference types="node" /> | ||
import { AuthenticationCredentialJSON, AuthenticatorDevice } from '@simplewebauthn/typescript-types'; | ||
import { AuthenticationCredentialJSON, AuthenticatorDevice, CredentialDeviceType } from '@simplewebauthn/typescript-types'; | ||
export declare type VerifyAuthenticationResponseOpts = { | ||
@@ -36,2 +36,7 @@ credential: AuthenticationCredentialJSON; | ||
* attacks!** | ||
* @param authenticationInfo.credentialDeviceType Whether this is a single-device or multi-device | ||
* credential. **Should be kept in a DB for later reference!** | ||
* @param authenticationInfo.credentialBackedUp Whether or not the multi-device credential has been | ||
* backed up. Always `false` for single-device credentials. **Should be kept in a DB for later | ||
* reference!** | ||
*/ | ||
@@ -43,3 +48,5 @@ export declare type VerifiedAuthenticationResponse = { | ||
newCounter: number; | ||
credentialDeviceType: CredentialDeviceType; | ||
credentialBackedUp: boolean; | ||
}; | ||
}; |
@@ -13,2 +13,3 @@ "use strict"; | ||
const isBase64URLString_1 = __importDefault(require("../helpers/isBase64URLString")); | ||
const parseBackupFlags_1 = require("../helpers/parseBackupFlags"); | ||
/** | ||
@@ -49,3 +50,3 @@ * Verify that the user has legitimately completed the login process | ||
} | ||
const clientDataJSON = decodeClientDataJSON_1.default(response.clientDataJSON); | ||
const clientDataJSON = (0, decodeClientDataJSON_1.default)(response.clientDataJSON); | ||
const { type, origin, challenge, tokenBinding } = clientDataJSON; | ||
@@ -77,6 +78,6 @@ // Make sure we're handling an authentication | ||
} | ||
if (!isBase64URLString_1.default(response.authenticatorData)) { | ||
if (!(0, isBase64URLString_1.default)(response.authenticatorData)) { | ||
throw new Error('Credential response authenticatorData was not a base64url string'); | ||
} | ||
if (!isBase64URLString_1.default(response.signature)) { | ||
if (!(0, isBase64URLString_1.default)(response.signature)) { | ||
throw new Error('Credential response signature was not a base64url string'); | ||
@@ -96,7 +97,7 @@ } | ||
const authDataBuffer = base64url_1.default.toBuffer(response.authenticatorData); | ||
const parsedAuthData = parseAuthenticatorData_1.default(authDataBuffer); | ||
const parsedAuthData = (0, parseAuthenticatorData_1.default)(authDataBuffer); | ||
const { rpIdHash, flags, counter } = parsedAuthData; | ||
// Make sure the response's RP ID is ours | ||
if (typeof expectedRPID === 'string') { | ||
const expectedRPIDHash = toHash_1.default(Buffer.from(expectedRPID, 'ascii')); | ||
const expectedRPIDHash = (0, toHash_1.default)(Buffer.from(expectedRPID, 'ascii')); | ||
if (!rpIdHash.equals(expectedRPIDHash)) { | ||
@@ -109,3 +110,3 @@ throw new Error(`Unexpected RP ID hash`); | ||
const foundMatch = expectedRPID.some(expected => { | ||
const expectedRPIDHash = toHash_1.default(Buffer.from(expected, 'ascii')); | ||
const expectedRPIDHash = (0, toHash_1.default)(Buffer.from(expected, 'ascii')); | ||
return rpIdHash.equals(expectedRPIDHash); | ||
@@ -125,5 +126,5 @@ }); | ||
} | ||
const clientDataHash = toHash_1.default(base64url_1.default.toBuffer(response.clientDataJSON)); | ||
const clientDataHash = (0, toHash_1.default)(base64url_1.default.toBuffer(response.clientDataJSON)); | ||
const signatureBase = Buffer.concat([authDataBuffer, clientDataHash]); | ||
const publicKey = convertPublicKeyToPEM_1.default(authenticator.credentialPublicKey); | ||
const publicKey = (0, convertPublicKeyToPEM_1.default)(authenticator.credentialPublicKey); | ||
const signature = base64url_1.default.toBuffer(response.signature); | ||
@@ -137,7 +138,10 @@ if ((counter > 0 || authenticator.counter > 0) && counter <= authenticator.counter) { | ||
} | ||
const { credentialDeviceType, credentialBackedUp } = (0, parseBackupFlags_1.parseBackupFlags)(flags); | ||
const toReturn = { | ||
verified: verifySignature_1.default(signature, signatureBase, publicKey), | ||
verified: (0, verifySignature_1.default)(signature, signatureBase, publicKey), | ||
authenticationInfo: { | ||
newCounter: counter, | ||
credentialID: authenticator.credentialID, | ||
credentialDeviceType, | ||
credentialBackedUp, | ||
}, | ||
@@ -144,0 +148,0 @@ }; |
@@ -9,3 +9,3 @@ "use strict"; | ||
function convertCOSEtoPKCS(cosePublicKey) { | ||
const struct = decodeCbor_1.decodeCborFirst(cosePublicKey); | ||
const struct = (0, decodeCbor_1.decodeCborFirst)(cosePublicKey); | ||
const tag = Buffer.from([0x04]); | ||
@@ -12,0 +12,0 @@ const x = struct.get(COSEKEYS.x); |
@@ -15,3 +15,4 @@ "use strict"; | ||
catch (err) { | ||
throw new Error(`Error decoding public key while converting to PEM: ${err.message}`); | ||
const _err = err; | ||
throw new Error(`Error decoding public key while converting to PEM: ${_err.message}`); | ||
} | ||
@@ -35,3 +36,3 @@ const kty = struct.get(convertCOSEtoPKCS_1.COSEKEYS.kty); | ||
} | ||
const ecPEM = jwk_to_pem_1.default({ | ||
const ecPEM = (0, jwk_to_pem_1.default)({ | ||
kty: 'EC', | ||
@@ -54,3 +55,3 @@ // Specify curve as "P-256" from "p256" | ||
} | ||
const rsaPEM = jwk_to_pem_1.default({ | ||
const rsaPEM = (0, jwk_to_pem_1.default)({ | ||
kty: 'RSA', | ||
@@ -57,0 +58,0 @@ n: n.toString('base64'), |
@@ -14,5 +14,6 @@ "use strict"; | ||
catch (err) { | ||
const _err = err; | ||
// if the error was due to extra bytes, return the unpacked value | ||
if (err.value) { | ||
return err.value; | ||
if (_err.value) { | ||
return _err.value; | ||
} | ||
@@ -23,2 +24,9 @@ throw err; | ||
exports.decodeCborFirst = decodeCborFirst; | ||
/** | ||
* Intuited from a quick scan of `cbor.decodeFirstSync()` here: | ||
* | ||
* https://github.com/hildjj/node-cbor/blob/v5.1.0/lib/decoder.js#L189 | ||
*/ | ||
class CborDecoderError extends Error { | ||
} | ||
//# sourceMappingURL=decodeCbor.js.map |
@@ -5,5 +5,5 @@ "use strict"; | ||
function decodeCredentialPublicKey(publicKey) { | ||
return decodeCbor_1.decodeCborFirst(publicKey); | ||
return (0, decodeCbor_1.decodeCborFirst)(publicKey); | ||
} | ||
exports.default = decodeCredentialPublicKey; | ||
//# sourceMappingURL=decodeCredentialPublicKey.js.map |
@@ -53,5 +53,5 @@ "use strict"; | ||
try { | ||
const respCRL = await node_fetch_1.default(crlURL[0]); | ||
const respCRL = await (0, node_fetch_1.default)(crlURL[0]); | ||
const dataCRL = await respCRL.buffer(); | ||
const dataPEM = convertCertBufferToPEM_1.default(dataCRL); | ||
const dataPEM = (0, convertCertBufferToPEM_1.default)(dataCRL); | ||
crlCert.readCertPEM(dataPEM); | ||
@@ -58,0 +58,0 @@ } |
@@ -8,3 +8,3 @@ "use strict"; | ||
const debug_1 = __importDefault(require("debug")); | ||
const defaultLogger = debug_1.default('SimpleWebAuthn'); | ||
const defaultLogger = (0, debug_1.default)('SimpleWebAuthn'); | ||
/** | ||
@@ -11,0 +11,0 @@ * Generate an instance of a `debug` logger that extends off of the "simplewebauthn" namespace for |
@@ -12,2 +12,4 @@ /// <reference types="node" /> | ||
uv: boolean; | ||
be: boolean; | ||
bs: boolean; | ||
at: boolean; | ||
@@ -14,0 +16,0 @@ ed: boolean; |
@@ -19,7 +19,11 @@ "use strict"; | ||
const flagsInt = flagsBuf[0]; | ||
// Bit positions can be referenced here: | ||
// https://www.w3.org/TR/webauthn-2/#flags | ||
const flags = { | ||
up: !!(flagsInt & 0x01), | ||
uv: !!(flagsInt & 0x04), | ||
at: !!(flagsInt & 0x40), | ||
ed: !!(flagsInt & 0x80), | ||
up: !!(flagsInt & 1 << 0), | ||
uv: !!(flagsInt & 1 << 2), | ||
be: !!(flagsInt & 1 << 3), | ||
bs: !!(flagsInt & 1 << 4), | ||
at: !!(flagsInt & 1 << 6), | ||
ed: !!(flagsInt & 1 << 7), | ||
flagsInt, | ||
@@ -38,3 +42,3 @@ }; | ||
// Decode the next CBOR item in the buffer, then re-encode it back to a Buffer | ||
const firstDecoded = decodeCbor_1.decodeCborFirst(authData.slice(pointer)); | ||
const firstDecoded = (0, decodeCbor_1.decodeCborFirst)(authData.slice(pointer)); | ||
const firstEncoded = Buffer.from(cbor_1.default.encode(firstDecoded)); | ||
@@ -46,3 +50,3 @@ credentialPublicKey = firstEncoded; | ||
if (flags.ed) { | ||
const firstDecoded = decodeCbor_1.decodeCborFirst(authData.slice(pointer)); | ||
const firstDecoded = (0, decodeCbor_1.decodeCborFirst)(authData.slice(pointer)); | ||
const firstEncoded = Buffer.from(cbor_1.default.encode(firstDecoded)); | ||
@@ -49,0 +53,0 @@ extensionsDataBuffer = firstEncoded; |
@@ -78,3 +78,3 @@ "use strict"; | ||
// Check for certificate revocation | ||
const subjectCertRevoked = await isCertRevoked_1.default(subjectCert); | ||
const subjectCertRevoked = await (0, isCertRevoked_1.default)(subjectCert); | ||
if (subjectCertRevoked) { | ||
@@ -84,4 +84,4 @@ throw new Error(`Found revoked certificate in certificate path`); | ||
// Check that intermediate certificate is within its valid time window | ||
const notBefore = jsrsasign_1.zulutodate(issuerCert.getNotBefore()); | ||
const notAfter = jsrsasign_1.zulutodate(issuerCert.getNotAfter()); | ||
const notBefore = (0, jsrsasign_1.zulutodate)(issuerCert.getNotBefore()); | ||
const notAfter = (0, jsrsasign_1.zulutodate)(issuerCert.getNotAfter()); | ||
const now = new Date(Date.now()); | ||
@@ -88,0 +88,0 @@ if (notBefore > now || notAfter < now) { |
@@ -25,3 +25,3 @@ "use strict"; | ||
// Extract the public key's COSE info for comparison | ||
const decodedPublicKey = decodeCredentialPublicKey_1.default(credentialPublicKey); | ||
const decodedPublicKey = (0, decodeCredentialPublicKey_1.default)(credentialPublicKey); | ||
// Assume everything is a number because these values should be | ||
@@ -64,6 +64,7 @@ const publicKeyCOSEInfo = { | ||
try { | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), statement.attestationRootCertificates.map(convertCertBufferToPEM_1.default)); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), statement.attestationRootCertificates.map(convertCertBufferToPEM_1.default)); | ||
} | ||
catch (err) { | ||
throw new Error(`Could not validate certificate path with any metadata root certificates: ${err.message}`); | ||
const _err = err; | ||
throw new Error(`Could not validate certificate path with any metadata root certificates: ${_err.message}`); | ||
} | ||
@@ -70,0 +71,0 @@ return true; |
@@ -74,3 +74,3 @@ "use strict"; | ||
function generateRegistrationOptions(options) { | ||
const { rpName, rpID, userID, userName, challenge = generateChallenge_1.default(), userDisplayName = userName, timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options; | ||
const { rpName, rpID, userID, userName, challenge = (0, generateChallenge_1.default)(), userDisplayName = userName, timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options; | ||
/** | ||
@@ -77,0 +77,0 @@ * Prepare pubKeyCredParams from the array of algorithm ID's |
@@ -45,7 +45,7 @@ "use strict"; | ||
} | ||
const parsedPubArea = parsePubArea_1.default(pubArea); | ||
const parsedPubArea = (0, parsePubArea_1.default)(pubArea); | ||
const { unique, type: pubType, parameters } = parsedPubArea; | ||
// Verify that the public key specified by the parameters and unique fields of pubArea is | ||
// identical to the credentialPublicKey in the attestedCredentialData in authenticatorData. | ||
const cosePublicKey = decodeCredentialPublicKey_1.default(credentialPublicKey); | ||
const cosePublicKey = (0, decodeCredentialPublicKey_1.default)(credentialPublicKey); | ||
if (pubType === 'TPM_ALG_RSA') { | ||
@@ -107,3 +107,3 @@ const n = cosePublicKey.get(convertCOSEtoPKCS_1.COSEKEYS.n); | ||
} | ||
const parsedCertInfo = parseCertInfo_1.default(certInfo); | ||
const parsedCertInfo = (0, parseCertInfo_1.default)(certInfo); | ||
const { magic, type: certType, attested, extraData } = parsedCertInfo; | ||
@@ -117,3 +117,3 @@ if (magic !== 0xff544347) { | ||
// Hash pubArea to create pubAreaHash using the nameAlg in attested | ||
const pubAreaHash = toHash_1.default(pubArea, attested.nameAlg.replace('TPM_ALG_', '')); | ||
const pubAreaHash = (0, toHash_1.default)(pubArea, attested.nameAlg.replace('TPM_ALG_', '')); | ||
// Concatenate attested.nameAlg and pubAreaHash to create attestedName. | ||
@@ -129,3 +129,3 @@ const attestedName = Buffer.concat([attested.nameAlgBuffer, pubAreaHash]); | ||
const hashAlg = convertCOSEtoPKCS_1.COSEALGHASH[alg]; | ||
const attToBeSignedHash = toHash_1.default(attToBeSigned, hashAlg); | ||
const attToBeSignedHash = (0, toHash_1.default)(attToBeSigned, hashAlg); | ||
// Check that certInfo.extraData is equals to attToBeSignedHash. | ||
@@ -142,3 +142,3 @@ if (!extraData.equals(attToBeSignedHash)) { | ||
// Pick a leaf AIK certificate of the x5c array and parse it. | ||
const leafCertInfo = getCertificateInfo_1.default(x5c[0]); | ||
const leafCertInfo = (0, getCertificateInfo_1.default)(x5c[0]); | ||
const { basicConstraintsCA, version, subject, notAfter, notBefore } = leafCertInfo; | ||
@@ -214,6 +214,7 @@ if (basicConstraintsCA) { | ||
try { | ||
await verifyAttestationWithMetadata_1.default(statement, credentialPublicKey, x5c); | ||
await (0, verifyAttestationWithMetadata_1.default)(statement, credentialPublicKey, x5c); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (TPM)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (TPM)`); | ||
} | ||
@@ -224,6 +225,7 @@ } | ||
// Try validating the certificate path using the root certificates set via SettingsService | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (TPM)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (TPM)`); | ||
} | ||
@@ -233,4 +235,4 @@ } | ||
// In the wise words of Yuriy Ackermann: "Get Martini friend, you are done!" | ||
const leafCertPEM = convertCertBufferToPEM_1.default(x5c[0]); | ||
return verifySignature_1.default(sig, certInfo, leafCertPEM, hashAlg); | ||
const leafCertPEM = (0, convertCertBufferToPEM_1.default)(x5c[0]); | ||
return (0, verifySignature_1.default)(sig, certInfo, leafCertPEM, hashAlg); | ||
} | ||
@@ -237,0 +239,0 @@ exports.default = verifyTPM; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
@@ -55,3 +59,3 @@ if (k2 === undefined) k2 = k; | ||
// Convert the credentialPublicKey to PKCS | ||
const credPubKeyPKCS = convertCOSEtoPKCS_1.default(credentialPublicKey); | ||
const credPubKeyPKCS = (0, convertCOSEtoPKCS_1.default)(credentialPublicKey); | ||
if (!credPubKeyPKCS.equals(parsedCertPubKey)) { | ||
@@ -82,6 +86,7 @@ throw new Error('Credential public key does not equal leaf cert public key (AndroidKey)'); | ||
try { | ||
await verifyAttestationWithMetadata_1.default(statement, credentialPublicKey, x5c); | ||
await (0, verifyAttestationWithMetadata_1.default)(statement, credentialPublicKey, x5c); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (AndroidKey)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (AndroidKey)`); | ||
} | ||
@@ -92,14 +97,15 @@ } | ||
// Try validating the certificate path using the root certificates set via SettingsService | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (AndroidKey)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (AndroidKey)`); | ||
} | ||
} | ||
const signatureBase = Buffer.concat([authData, clientDataHash]); | ||
const leafCertPEM = convertCertBufferToPEM_1.default(x5c[0]); | ||
const leafCertPEM = (0, convertCertBufferToPEM_1.default)(x5c[0]); | ||
const hashAlg = convertCOSEtoPKCS_1.COSEALGHASH[alg]; | ||
return verifySignature_1.default(sig, signatureBase, leafCertPEM, hashAlg); | ||
return (0, verifySignature_1.default)(sig, signatureBase, leafCertPEM, hashAlg); | ||
} | ||
exports.default = verifyAttestationAndroidKey; | ||
//# sourceMappingURL=verifyAndroidKey.js.map |
@@ -50,3 +50,3 @@ "use strict"; | ||
const nonceBase = Buffer.concat([authData, clientDataHash]); | ||
const nonceBuffer = toHash_1.default(nonceBase); | ||
const nonceBuffer = (0, toHash_1.default)(nonceBase); | ||
const expectedNonce = nonceBuffer.toString('base64'); | ||
@@ -66,3 +66,3 @@ if (nonce !== expectedNonce) { | ||
const leafCertBuffer = base64url_1.default.toBuffer(HEADER.x5c[0]); | ||
const leafCertInfo = getCertificateInfo_1.default(leafCertBuffer); | ||
const leafCertInfo = (0, getCertificateInfo_1.default)(leafCertBuffer); | ||
const { subject } = leafCertInfo; | ||
@@ -77,6 +77,7 @@ // Ensure the certificate was issued to this hostname | ||
try { | ||
await verifyAttestationWithMetadata_1.default(statement, credentialPublicKey, HEADER.x5c); | ||
await (0, verifyAttestationWithMetadata_1.default)(statement, credentialPublicKey, HEADER.x5c); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (SafetyNet)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (SafetyNet)`); | ||
} | ||
@@ -87,6 +88,7 @@ } | ||
// Try validating the certificate path using the root certificates set via SettingsService | ||
await validateCertificatePath_1.default(HEADER.x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(HEADER.x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (SafetyNet)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (SafetyNet)`); | ||
} | ||
@@ -102,4 +104,4 @@ } | ||
const signatureBuffer = base64url_1.default.toBuffer(SIGNATURE); | ||
const leafCertPEM = convertCertBufferToPEM_1.default(leafCertBuffer); | ||
const verified = verifySignature_1.default(signatureBuffer, signatureBaseBuffer, leafCertPEM); | ||
const leafCertPEM = (0, convertCertBufferToPEM_1.default)(leafCertBuffer); | ||
const verified = (0, verifySignature_1.default)(signatureBuffer, signatureBaseBuffer, leafCertPEM); | ||
/** | ||
@@ -106,0 +108,0 @@ * END Verify Signature |
@@ -22,6 +22,7 @@ "use strict"; | ||
try { | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (Apple)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (Apple)`); | ||
} | ||
@@ -41,3 +42,3 @@ /** | ||
const nonceToHash = Buffer.concat([authData, clientDataHash]); | ||
const nonce = toHash_1.default(nonceToHash, 'SHA256'); | ||
const nonce = (0, toHash_1.default)(nonceToHash, 'SHA256'); | ||
/** | ||
@@ -57,3 +58,3 @@ * Ignore the first six ASN.1 structure bytes that define the nonce as an OCTET STRING. Should | ||
*/ | ||
const credPubKeyPKCS = convertCOSEtoPKCS_1.default(credentialPublicKey); | ||
const credPubKeyPKCS = (0, convertCOSEtoPKCS_1.default)(credentialPublicKey); | ||
const credCertSubjectPublicKey = Buffer.from(subjectPublicKeyInfo.subjectPublicKey); | ||
@@ -60,0 +61,0 @@ if (!credPubKeyPKCS.equals(credCertSubjectPublicKey)) { |
@@ -16,3 +16,3 @@ "use strict"; | ||
const reservedByte = Buffer.from([0x00]); | ||
const publicKey = convertCOSEtoPKCS_1.default(credentialPublicKey); | ||
const publicKey = (0, convertCOSEtoPKCS_1.default)(credentialPublicKey); | ||
const signatureBase = Buffer.concat([ | ||
@@ -39,11 +39,12 @@ reservedByte, | ||
// Try validating the certificate path using the root certificates set via SettingsService | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (FIDOU2F)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (FIDOU2F)`); | ||
} | ||
const leafCertPEM = convertCertBufferToPEM_1.default(x5c[0]); | ||
return verifySignature_1.default(sig, signatureBase, leafCertPEM); | ||
const leafCertPEM = (0, convertCertBufferToPEM_1.default)(x5c[0]); | ||
return (0, verifySignature_1.default)(sig, signatureBase, leafCertPEM); | ||
} | ||
exports.default = verifyAttestationFIDOU2F; | ||
//# sourceMappingURL=verifyFIDOU2F.js.map |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
@@ -50,6 +54,6 @@ if (k2 === undefined) k2 = k; | ||
let verified = false; | ||
const pkcsPublicKey = convertCOSEtoPKCS_1.default(credentialPublicKey); | ||
const pkcsPublicKey = (0, convertCOSEtoPKCS_1.default)(credentialPublicKey); | ||
if (x5c) { | ||
const leafCert = convertCertBufferToPEM_1.default(x5c[0]); | ||
const { subject, basicConstraintsCA, version, notBefore, notAfter } = getCertificateInfo_1.default(x5c[0]); | ||
const leafCert = (0, convertCertBufferToPEM_1.default)(x5c[0]); | ||
const { subject, basicConstraintsCA, version, notBefore, notAfter } = (0, getCertificateInfo_1.default)(x5c[0]); | ||
const { OU, CN, O, C } = subject; | ||
@@ -93,6 +97,7 @@ if (OU !== 'Authenticator Attestation') { | ||
try { | ||
await verifyAttestationWithMetadata_1.default(statement, credentialPublicKey, x5c); | ||
await (0, verifyAttestationWithMetadata_1.default)(statement, credentialPublicKey, x5c); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (Packed|Full)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (Packed|Full)`); | ||
} | ||
@@ -103,12 +108,13 @@ } | ||
// Try validating the certificate path using the root certificates set via SettingsService | ||
await validateCertificatePath_1.default(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
await (0, validateCertificatePath_1.default)(x5c.map(convertCertBufferToPEM_1.default), rootCertificates); | ||
} | ||
catch (err) { | ||
throw new Error(`${err.message} (Packed|Full)`); | ||
const _err = err; | ||
throw new Error(`${_err.message} (Packed|Full)`); | ||
} | ||
} | ||
verified = verifySignature_1.default(sig, signatureBase, leafCert); | ||
verified = (0, verifySignature_1.default)(sig, signatureBase, leafCert); | ||
} | ||
else { | ||
const cosePublicKey = decodeCredentialPublicKey_1.default(credentialPublicKey); | ||
const cosePublicKey = (0, decodeCredentialPublicKey_1.default)(credentialPublicKey); | ||
const kty = cosePublicKey.get(convertCOSEtoPKCS_1.COSEKEYS.kty); | ||
@@ -124,3 +130,3 @@ if (!kty) { | ||
} | ||
const signatureBaseHash = toHash_1.default(signatureBase, hashAlg); | ||
const signatureBaseHash = (0, toHash_1.default)(signatureBase, hashAlg); | ||
/** | ||
@@ -159,3 +165,3 @@ * Instantiating the curve here is _very_ computationally heavy - a bit of profiling | ||
} | ||
const signatureBaseHash = toHash_1.default(signatureBase, hashAlg); | ||
const signatureBaseHash = (0, toHash_1.default)(signatureBase, hashAlg); | ||
const key = new elliptic_1.default.eddsa('ed25519'); | ||
@@ -162,0 +168,0 @@ key.keyFromPublic(x); |
/// <reference types="node" /> | ||
import { RegistrationCredentialJSON, COSEAlgorithmIdentifier } from '@simplewebauthn/typescript-types'; | ||
import { RegistrationCredentialJSON, COSEAlgorithmIdentifier, CredentialDeviceType } from '@simplewebauthn/typescript-types'; | ||
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject'; | ||
@@ -34,3 +34,3 @@ export declare type VerifyRegistrationResponseOpts = { | ||
* @param registrationInfo.counter The number of times the authenticator reported it has been used. | ||
* Should be kept in a DB for later reference to help prevent replay attacks | ||
* **Should be kept in a DB for later reference to help prevent replay attacks!** | ||
* @param registrationInfo.aaguid Authenticator's Attestation GUID indicating the type of the | ||
@@ -44,2 +44,7 @@ * authenticator | ||
* the authenticator | ||
* @param registrationInfo.credentialDeviceType Whether this is a single-device or multi-device | ||
* credential. **Should be kept in a DB for later reference!** | ||
* @param registrationInfo.credentialBackedUp Whether or not the multi-device credential has been | ||
* backed up. Always `false` for single-device credentials. **Should be kept in a DB for later | ||
* reference!** | ||
*/ | ||
@@ -52,7 +57,9 @@ export declare type VerifiedRegistrationResponse = { | ||
aaguid: string; | ||
credentialID: Buffer; | ||
credentialPublicKey: Buffer; | ||
credentialID: Buffer; | ||
credentialType: string; | ||
credentialType: "public-key"; | ||
attestationObject: Buffer; | ||
userVerified: boolean; | ||
attestationObject: Buffer; | ||
credentialDeviceType: CredentialDeviceType; | ||
credentialBackedUp: boolean; | ||
}; | ||
@@ -59,0 +66,0 @@ }; |
@@ -14,2 +14,3 @@ "use strict"; | ||
const convertAAGUIDToString_1 = __importDefault(require("../helpers/convertAAGUIDToString")); | ||
const parseBackupFlags_1 = require("../helpers/parseBackupFlags"); | ||
const settingsService_1 = __importDefault(require("../services/settingsService")); | ||
@@ -53,3 +54,3 @@ const generateRegistrationOptions_1 = require("./generateRegistrationOptions"); | ||
} | ||
const clientDataJSON = decodeClientDataJSON_1.default(response.clientDataJSON); | ||
const clientDataJSON = (0, decodeClientDataJSON_1.default)(response.clientDataJSON); | ||
const { type, origin, challenge, tokenBinding } = clientDataJSON; | ||
@@ -89,5 +90,5 @@ // Make sure we're handling an registration | ||
const attestationObject = base64url_1.default.toBuffer(response.attestationObject); | ||
const decodedAttestationObject = decodeAttestationObject_1.default(attestationObject); | ||
const decodedAttestationObject = (0, decodeAttestationObject_1.default)(attestationObject); | ||
const { fmt, authData, attStmt } = decodedAttestationObject; | ||
const parsedAuthData = parseAuthenticatorData_1.default(authData); | ||
const parsedAuthData = (0, parseAuthenticatorData_1.default)(authData); | ||
const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey } = parsedAuthData; | ||
@@ -97,3 +98,3 @@ // Make sure the response's RP ID is ours | ||
if (typeof expectedRPID === 'string') { | ||
const expectedRPIDHash = toHash_1.default(Buffer.from(expectedRPID, 'ascii')); | ||
const expectedRPIDHash = (0, toHash_1.default)(Buffer.from(expectedRPID, 'ascii')); | ||
if (!rpIdHash.equals(expectedRPIDHash)) { | ||
@@ -106,3 +107,3 @@ throw new Error(`Unexpected RP ID hash`); | ||
const foundMatch = expectedRPID.some(expected => { | ||
const expectedRPIDHash = toHash_1.default(Buffer.from(expected, 'ascii')); | ||
const expectedRPIDHash = (0, toHash_1.default)(Buffer.from(expected, 'ascii')); | ||
return rpIdHash.equals(expectedRPIDHash); | ||
@@ -132,3 +133,3 @@ }); | ||
} | ||
const decodedPublicKey = decodeCredentialPublicKey_1.default(credentialPublicKey); | ||
const decodedPublicKey = (0, decodeCredentialPublicKey_1.default)(credentialPublicKey); | ||
const alg = decodedPublicKey.get(convertCOSEtoPKCS_1.COSEKEYS.alg); | ||
@@ -143,3 +144,3 @@ if (typeof alg !== 'number') { | ||
} | ||
const clientDataHash = toHash_1.default(base64url_1.default.toBuffer(response.clientDataJSON)); | ||
const clientDataHash = (0, toHash_1.default)(base64url_1.default.toBuffer(response.clientDataJSON)); | ||
const rootCertificates = settingsService_1.default.getRootCertificates({ identifier: fmt }); | ||
@@ -162,18 +163,18 @@ // Prepare arguments to pass to the relevant verification method | ||
if (fmt === 'fido-u2f') { | ||
verified = await verifyFIDOU2F_1.default(verifierOpts); | ||
verified = await (0, verifyFIDOU2F_1.default)(verifierOpts); | ||
} | ||
else if (fmt === 'packed') { | ||
verified = await verifyPacked_1.default(verifierOpts); | ||
verified = await (0, verifyPacked_1.default)(verifierOpts); | ||
} | ||
else if (fmt === 'android-safetynet') { | ||
verified = await verifyAndroidSafetyNet_1.default(verifierOpts); | ||
verified = await (0, verifyAndroidSafetyNet_1.default)(verifierOpts); | ||
} | ||
else if (fmt === 'android-key') { | ||
verified = await verifyAndroidKey_1.default(verifierOpts); | ||
verified = await (0, verifyAndroidKey_1.default)(verifierOpts); | ||
} | ||
else if (fmt === 'tpm') { | ||
verified = await verifyTPM_1.default(verifierOpts); | ||
verified = await (0, verifyTPM_1.default)(verifierOpts); | ||
} | ||
else if (fmt === 'apple') { | ||
verified = await verifyApple_1.default(verifierOpts); | ||
verified = await (0, verifyApple_1.default)(verifierOpts); | ||
} | ||
@@ -194,11 +195,14 @@ else if (fmt === 'none') { | ||
if (toReturn.verified) { | ||
const { credentialDeviceType, credentialBackedUp } = (0, parseBackupFlags_1.parseBackupFlags)(flags); | ||
toReturn.registrationInfo = { | ||
fmt, | ||
counter, | ||
aaguid: convertAAGUIDToString_1.default(aaguid), | ||
aaguid: (0, convertAAGUIDToString_1.default)(aaguid), | ||
credentialID, | ||
credentialPublicKey, | ||
credentialID, | ||
credentialType, | ||
attestationObject, | ||
userVerified: flags.uv, | ||
attestationObject, | ||
credentialDeviceType, | ||
credentialBackedUp, | ||
}; | ||
@@ -205,0 +209,0 @@ } |
@@ -22,3 +22,3 @@ "use strict"; | ||
})(SERVICE_STATE || (SERVICE_STATE = {})); | ||
const log = logging_1.getLogger('MetadataService'); | ||
const log = (0, logging_1.getLogger)('MetadataService'); | ||
/** | ||
@@ -115,3 +115,3 @@ * A basic service for coordinating interactions with the FIDO Metadata Service. This includes BLOB | ||
if (aaguid instanceof Buffer) { | ||
aaguid = convertAAGUIDToString_1.default(aaguid); | ||
aaguid = (0, convertAAGUIDToString_1.default)(aaguid); | ||
} | ||
@@ -163,6 +163,6 @@ // If a cache refresh is in progress then pause this until the service is ready | ||
// Get latest "BLOB" (FIDO's terminology, not mine) | ||
const resp = await node_fetch_1.default(url); | ||
const resp = await (0, node_fetch_1.default)(url); | ||
const data = await resp.text(); | ||
// Parse the JWT | ||
const parsedJWT = parseJWT_1.default(data); | ||
const parsedJWT = (0, parseJWT_1.default)(data); | ||
const header = parsedJWT[0]; | ||
@@ -179,3 +179,3 @@ const payload = parsedJWT[1]; | ||
const rootCerts = settingsService_1.default.getRootCertificates({ identifier: 'mds' }); | ||
await validateCertificatePath_1.default(headerCertsPEM, rootCerts); | ||
await (0, validateCertificatePath_1.default)(headerCertsPEM, rootCerts); | ||
} | ||
@@ -182,0 +182,0 @@ catch (error) { |
@@ -27,3 +27,3 @@ "use strict"; | ||
if (cert instanceof Buffer) { | ||
newCertificates.push(convertCertBufferToPEM_1.default(cert)); | ||
newCertificates.push((0, convertCertBufferToPEM_1.default)(cert)); | ||
} | ||
@@ -30,0 +30,0 @@ else { |
{ | ||
"name": "@simplewebauthn/server", | ||
"version": "5.1.0", | ||
"version": "5.2.0", | ||
"description": "SimpleWebAuthn for Servers", | ||
@@ -49,6 +49,6 @@ "main": "dist/index.js", | ||
"dependencies": { | ||
"@peculiar/asn1-android": "^2.0.38", | ||
"@peculiar/asn1-schema": "^2.0.38", | ||
"@peculiar/asn1-x509": "^2.0.38", | ||
"@simplewebauthn/typescript-types": "^5.0.0", | ||
"@peculiar/asn1-android": "^2.1.7", | ||
"@peculiar/asn1-schema": "^2.1.7", | ||
"@peculiar/asn1-x509": "^2.1.7", | ||
"@simplewebauthn/typescript-types": "^5.2.0", | ||
"base64url": "^3.0.1", | ||
@@ -63,3 +63,3 @@ "cbor": "^5.1.0", | ||
}, | ||
"gitHead": "3393143f68ecb428d61f43d2fa65915fbd38fa49", | ||
"gitHead": "c93517488b6efec5c72ff212b834f4c6138ad494", | ||
"devDependencies": { | ||
@@ -66,0 +66,0 @@ "@types/cbor": "^5.0.1", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
249318
129
3891