@simplewebauthn/server 7.4.0 → 8.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +11 -14
- package/README.md +6 -2
- package/{dist → esm}/authentication/generateAuthenticationOptions.d.ts +2 -2
- package/esm/authentication/generateAuthenticationOptions.js +36 -0
- package/{dist → esm}/authentication/verifyAuthenticationResponse.d.ts +2 -2
- package/esm/authentication/verifyAuthenticationResponse.js +164 -0
- package/esm/deps.d.ts +10 -0
- package/esm/deps.js +12 -0
- package/esm/helpers/convertAAGUIDToString.js +17 -0
- package/esm/helpers/convertCOSEtoPKCS.js +21 -0
- package/{dist → esm}/helpers/convertCertBufferToPEM.d.ts +1 -1
- package/esm/helpers/convertCertBufferToPEM.js +31 -0
- package/esm/helpers/convertPEMToBytes.js +11 -0
- package/{dist → esm}/helpers/convertX509PublicKeyToCOSE.d.ts +1 -1
- package/esm/helpers/convertX509PublicKeyToCOSE.js +70 -0
- package/{dist → esm}/helpers/cose.d.ts +2 -1
- package/esm/helpers/cose.js +81 -0
- package/{dist → esm}/helpers/decodeAttestationObject.d.ts +3 -0
- package/esm/helpers/decodeAttestationObject.js +13 -0
- package/esm/helpers/decodeAuthenticatorExtensions.js +34 -0
- package/{dist → esm}/helpers/decodeClientDataJSON.d.ts +3 -0
- package/esm/helpers/decodeClientDataJSON.js +13 -0
- package/esm/helpers/decodeCredentialPublicKey.d.ts +5 -0
- package/esm/helpers/decodeCredentialPublicKey.js +8 -0
- package/esm/helpers/fetch.d.ts +8 -0
- package/esm/helpers/fetch.js +12 -0
- package/esm/helpers/generateChallenge.d.ts +7 -0
- package/esm/helpers/generateChallenge.js +21 -0
- package/{dist → esm}/helpers/getCertificateInfo.d.ts +1 -1
- package/esm/helpers/getCertificateInfo.js +76 -0
- package/esm/helpers/index.d.ts +22 -0
- package/esm/helpers/index.js +16 -0
- package/{dist → esm}/helpers/isCertRevoked.d.ts +1 -1
- package/esm/helpers/isCertRevoked.js +98 -0
- package/{dist → esm}/helpers/iso/index.d.ts +4 -4
- package/esm/helpers/iso/index.js +11 -0
- package/esm/helpers/iso/isoBase64URL.js +57 -0
- package/{dist → esm}/helpers/iso/isoCBOR.d.ts +1 -1
- package/esm/helpers/iso/isoCBOR.js +44 -0
- package/{dist → esm}/helpers/iso/isoCrypto/digest.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/digest.js +14 -0
- package/{dist → esm}/helpers/iso/isoCrypto/getRandomValues.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/getRandomValues.js +11 -0
- package/esm/helpers/iso/isoCrypto/getWebCrypto.d.ts +6 -0
- package/esm/helpers/iso/isoCrypto/getWebCrypto.js +40 -0
- package/esm/helpers/iso/isoCrypto/importKey.js +8 -0
- package/esm/helpers/iso/isoCrypto/index.d.ts +3 -0
- package/esm/helpers/iso/isoCrypto/index.js +3 -0
- package/{dist → esm}/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.d.ts +2 -2
- package/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.js +20 -0
- package/{dist → esm}/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.d.ts +2 -2
- package/esm/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js +19 -0
- package/esm/helpers/iso/isoCrypto/structs.js +1 -0
- package/esm/helpers/iso/isoCrypto/unwrapEC2Signature.js +30 -0
- package/{dist → esm}/helpers/iso/isoCrypto/verify.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/verify.js +28 -0
- package/{dist → esm}/helpers/iso/isoCrypto/verifyEC2.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/verifyEC2.js +73 -0
- package/{dist → esm}/helpers/iso/isoCrypto/verifyOKP.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/verifyOKP.js +51 -0
- package/{dist → esm}/helpers/iso/isoCrypto/verifyRSA.d.ts +1 -1
- package/esm/helpers/iso/isoCrypto/verifyRSA.js +91 -0
- package/esm/helpers/iso/isoUint8Array.js +75 -0
- package/{dist → esm}/helpers/logging.d.ts +1 -1
- package/esm/helpers/logging.js +19 -0
- package/{dist → esm}/helpers/mapX509SignatureAlgToCOSEAlg.d.ts +1 -1
- package/esm/helpers/mapX509SignatureAlgToCOSEAlg.js +35 -0
- package/esm/helpers/matchExpectedRPID.js +41 -0
- package/{dist → esm}/helpers/parseAuthenticatorData.d.ts +4 -1
- package/esm/helpers/parseAuthenticatorData.js +71 -0
- package/{dist → esm}/helpers/parseBackupFlags.d.ts +4 -1
- package/esm/helpers/parseBackupFlags.js +25 -0
- package/{dist → esm}/helpers/toHash.d.ts +1 -1
- package/esm/helpers/toHash.js +12 -0
- package/esm/helpers/validateCertificatePath.js +122 -0
- package/{dist → esm}/helpers/verifySignature.d.ts +4 -1
- package/esm/helpers/verifySignature.js +32 -0
- package/esm/index.d.ts +17 -0
- package/esm/index.js +11 -0
- package/{dist → esm}/metadata/mdsTypes.d.ts +1 -1
- package/esm/metadata/mdsTypes.js +17 -0
- package/esm/metadata/parseJWT.js +12 -0
- package/{dist → esm}/metadata/verifyAttestationWithMetadata.d.ts +3 -3
- package/esm/metadata/verifyAttestationWithMetadata.js +159 -0
- package/esm/metadata/verifyJWT.js +37 -0
- package/esm/package.json +3 -0
- package/{dist → esm}/registration/generateRegistrationOptions.d.ts +2 -2
- package/esm/registration/generateRegistrationOptions.js +142 -0
- package/esm/registration/verifications/tpm/constants.js +182 -0
- package/esm/registration/verifications/tpm/parseCertInfo.js +58 -0
- package/esm/registration/verifications/tpm/parsePubArea.js +94 -0
- package/{dist → esm}/registration/verifications/tpm/verifyAttestationTPM.d.ts +1 -1
- package/esm/registration/verifications/tpm/verifyAttestationTPM.js +323 -0
- package/{dist → esm}/registration/verifications/verifyAttestationAndroidKey.d.ts +1 -1
- package/esm/registration/verifications/verifyAttestationAndroidKey.js +90 -0
- package/{dist → esm}/registration/verifications/verifyAttestationAndroidSafetyNet.d.ts +1 -1
- package/esm/registration/verifications/verifyAttestationAndroidSafetyNet.js +112 -0
- package/{dist → esm}/registration/verifications/verifyAttestationApple.d.ts +1 -1
- package/esm/registration/verifications/verifyAttestationApple.js +57 -0
- package/{dist → esm}/registration/verifications/verifyAttestationFIDOU2F.d.ts +1 -1
- package/esm/registration/verifications/verifyAttestationFIDOU2F.js +48 -0
- package/{dist → esm}/registration/verifications/verifyAttestationPacked.d.ts +1 -1
- package/esm/registration/verifications/verifyAttestationPacked.js +105 -0
- package/{dist → esm}/registration/verifyRegistrationResponse.d.ts +3 -3
- package/esm/registration/verifyRegistrationResponse.js +198 -0
- package/esm/services/defaultRootCerts/android-key.js +85 -0
- package/esm/services/defaultRootCerts/android-safetynet.js +32 -0
- package/esm/services/defaultRootCerts/apple.js +25 -0
- package/esm/services/defaultRootCerts/mds.js +32 -0
- package/{dist → esm}/services/metadataService.d.ts +1 -1
- package/{dist → esm}/services/metadataService.js +52 -36
- package/{dist → esm}/services/settingsService.d.ts +1 -1
- package/esm/services/settingsService.js +65 -0
- package/package.json +40 -45
- package/script/authentication/generateAuthenticationOptions.d.ts +23 -0
- package/{dist → script}/authentication/generateAuthenticationOptions.js +8 -9
- package/script/authentication/verifyAuthenticationResponse.d.ts +66 -0
- package/{dist → script}/authentication/verifyAuthenticationResponse.js +25 -23
- package/script/deps.d.ts +10 -0
- package/script/deps.js +68 -0
- package/script/helpers/convertAAGUIDToString.d.ts +4 -0
- package/{dist → script}/helpers/convertAAGUIDToString.js +2 -3
- package/script/helpers/convertCOSEtoPKCS.d.ts +4 -0
- package/{dist → script}/helpers/convertCOSEtoPKCS.js +7 -8
- package/script/helpers/convertCertBufferToPEM.d.ts +5 -0
- package/{dist → script}/helpers/convertCertBufferToPEM.js +5 -6
- package/script/helpers/convertPEMToBytes.d.ts +4 -0
- package/{dist → script}/helpers/convertPEMToBytes.js +2 -3
- package/script/helpers/convertX509PublicKeyToCOSE.d.ts +2 -0
- package/{dist → script}/helpers/convertX509PublicKeyToCOSE.js +21 -25
- package/script/helpers/cose.d.ts +98 -0
- package/{dist → script}/helpers/cose.js +1 -1
- package/script/helpers/decodeAttestationObject.d.ts +29 -0
- package/script/helpers/decodeAttestationObject.js +17 -0
- package/script/helpers/decodeAuthenticatorExtensions.d.ts +20 -0
- package/{dist → script}/helpers/decodeAuthenticatorExtensions.js +2 -3
- package/script/helpers/decodeClientDataJSON.d.ts +17 -0
- package/script/helpers/decodeClientDataJSON.js +17 -0
- package/script/helpers/decodeCredentialPublicKey.d.ts +5 -0
- package/script/helpers/decodeCredentialPublicKey.js +12 -0
- package/script/helpers/fetch.d.ts +8 -0
- package/script/helpers/fetch.js +16 -0
- package/script/helpers/generateChallenge.d.ts +7 -0
- package/{dist → script}/helpers/generateChallenge.js +9 -6
- package/script/helpers/getCertificateInfo.d.ts +31 -0
- package/{dist → script}/helpers/getCertificateInfo.js +4 -6
- package/script/helpers/index.d.ts +22 -0
- package/script/helpers/index.js +59 -0
- package/script/helpers/isCertRevoked.d.ts +8 -0
- package/{dist → script}/helpers/isCertRevoked.js +20 -25
- package/script/helpers/iso/index.d.ts +11 -0
- package/{dist → script}/helpers/iso/index.js +4 -5
- package/script/helpers/iso/isoBase64URL.d.ts +37 -0
- package/{dist → script}/helpers/iso/isoBase64URL.js +0 -1
- package/script/helpers/iso/isoCBOR.d.ts +12 -0
- package/{dist → script}/helpers/iso/isoCBOR.js +8 -28
- package/script/helpers/iso/isoCrypto/digest.d.ts +8 -0
- package/script/helpers/iso/isoCrypto/digest.js +18 -0
- package/script/helpers/iso/isoCrypto/getRandomValues.d.ts +6 -0
- package/script/helpers/iso/isoCrypto/getRandomValues.js +15 -0
- package/script/helpers/iso/isoCrypto/getWebCrypto.d.ts +6 -0
- package/script/helpers/iso/isoCrypto/getWebCrypto.js +44 -0
- package/script/helpers/iso/isoCrypto/importKey.d.ts +4 -0
- package/script/helpers/iso/isoCrypto/importKey.js +12 -0
- package/script/helpers/iso/isoCrypto/index.d.ts +3 -0
- package/{dist → script}/helpers/iso/isoCrypto/index.js +6 -7
- package/script/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.d.ts +6 -0
- package/{dist → script}/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.js +6 -6
- package/script/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.d.ts +6 -0
- package/{dist → script}/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js +5 -6
- package/script/helpers/iso/isoCrypto/structs.d.ts +3 -0
- package/{dist → script}/helpers/iso/isoCrypto/structs.js +0 -1
- package/script/helpers/iso/isoCrypto/unwrapEC2Signature.d.ts +6 -0
- package/{dist → script}/helpers/iso/isoCrypto/unwrapEC2Signature.js +4 -6
- package/script/helpers/iso/isoCrypto/verify.d.ts +10 -0
- package/script/helpers/iso/isoCrypto/verify.js +32 -0
- package/script/helpers/iso/isoCrypto/verifyEC2.d.ts +10 -0
- package/{dist → script}/helpers/iso/isoCrypto/verifyEC2.js +19 -22
- package/script/helpers/iso/isoCrypto/verifyOKP.d.ts +6 -0
- package/{dist → script}/helpers/iso/isoCrypto/verifyOKP.js +13 -16
- package/script/helpers/iso/isoCrypto/verifyRSA.d.ts +10 -0
- package/{dist → script}/helpers/iso/isoCrypto/verifyRSA.js +19 -22
- package/script/helpers/iso/isoUint8Array.d.ts +36 -0
- package/{dist → script}/helpers/iso/isoUint8Array.js +7 -8
- package/script/helpers/logging.d.ts +17 -0
- package/{dist → script}/helpers/logging.js +2 -6
- package/script/helpers/mapX509SignatureAlgToCOSEAlg.d.ts +8 -0
- package/{dist → script}/helpers/mapX509SignatureAlgToCOSEAlg.js +8 -9
- package/script/helpers/matchExpectedRPID.d.ts +7 -0
- package/{dist → script}/helpers/matchExpectedRPID.js +5 -6
- package/script/helpers/parseAuthenticatorData.d.ts +28 -0
- package/{dist → script}/helpers/parseAuthenticatorData.js +19 -16
- package/script/helpers/parseBackupFlags.d.ts +19 -0
- package/{dist → script}/helpers/parseBackupFlags.js +2 -2
- package/script/helpers/toHash.d.ts +6 -0
- package/{dist → script}/helpers/toHash.js +4 -5
- package/script/helpers/validateCertificatePath.d.ts +6 -0
- package/{dist → script}/helpers/validateCertificatePath.js +13 -15
- package/script/helpers/verifySignature.d.ts +14 -0
- package/script/helpers/verifySignature.js +36 -0
- package/script/index.d.ts +17 -0
- package/script/index.js +19 -0
- package/script/metadata/mdsTypes.d.ts +216 -0
- package/{dist → script}/metadata/mdsTypes.js +0 -1
- package/script/metadata/parseJWT.d.ts +4 -0
- package/{dist → script}/metadata/parseJWT.js +3 -4
- package/script/metadata/verifyAttestationWithMetadata.d.ts +29 -0
- package/{dist → script}/metadata/verifyAttestationWithMetadata.js +24 -22
- package/script/metadata/verifyJWT.d.ts +10 -0
- package/script/metadata/verifyJWT.js +41 -0
- package/script/package.json +3 -0
- package/script/registration/generateRegistrationOptions.d.ts +43 -0
- package/{dist → script}/registration/generateRegistrationOptions.js +9 -10
- package/script/registration/verifications/tpm/constants.d.ts +47 -0
- package/{dist → script}/registration/verifications/tpm/constants.js +1 -2
- package/script/registration/verifications/tpm/parseCertInfo.d.ts +24 -0
- package/{dist → script}/registration/verifications/tpm/parseCertInfo.js +13 -14
- package/script/registration/verifications/tpm/parsePubArea.d.ts +43 -0
- package/{dist → script}/registration/verifications/tpm/parsePubArea.js +16 -17
- package/script/registration/verifications/tpm/verifyAttestationTPM.d.ts +2 -0
- package/{dist → script}/registration/verifications/tpm/verifyAttestationTPM.js +58 -58
- package/script/registration/verifications/verifyAttestationAndroidKey.d.ts +5 -0
- package/{dist → script}/registration/verifications/verifyAttestationAndroidKey.js +22 -26
- package/script/registration/verifications/verifyAttestationAndroidSafetyNet.d.ts +5 -0
- package/{dist → script}/registration/verifications/verifyAttestationAndroidSafetyNet.js +22 -23
- package/script/registration/verifications/verifyAttestationApple.d.ts +2 -0
- package/{dist → script}/registration/verifications/verifyAttestationApple.js +15 -17
- package/script/registration/verifications/verifyAttestationFIDOU2F.d.ts +5 -0
- package/{dist → script}/registration/verifications/verifyAttestationFIDOU2F.js +12 -13
- package/script/registration/verifications/verifyAttestationPacked.d.ts +5 -0
- package/{dist → script}/registration/verifications/verifyAttestationPacked.js +17 -18
- package/script/registration/verifyRegistrationResponse.d.ts +85 -0
- package/{dist → script}/registration/verifyRegistrationResponse.js +39 -38
- package/script/services/defaultRootCerts/android-key.d.ts +24 -0
- package/{dist → script}/services/defaultRootCerts/android-key.js +0 -1
- package/script/services/defaultRootCerts/android-safetynet.d.ts +11 -0
- package/{dist → script}/services/defaultRootCerts/android-safetynet.js +0 -1
- package/script/services/defaultRootCerts/apple.d.ts +11 -0
- package/{dist → script}/services/defaultRootCerts/apple.js +0 -1
- package/script/services/defaultRootCerts/mds.d.ts +11 -0
- package/{dist → script}/services/defaultRootCerts/mds.js +0 -1
- package/script/services/metadataService.d.ts +53 -0
- package/script/services/metadataService.js +277 -0
- package/script/services/settingsService.d.ts +25 -0
- package/{dist → script}/services/settingsService.js +21 -13
- package/dist/authentication/generateAuthenticationOptions.js.map +0 -1
- package/dist/authentication/verifyAuthenticationResponse.js.map +0 -1
- package/dist/helpers/convertAAGUIDToString.js.map +0 -1
- package/dist/helpers/convertCOSEtoPKCS.js.map +0 -1
- package/dist/helpers/convertCertBufferToPEM.js.map +0 -1
- package/dist/helpers/convertPEMToBytes.js.map +0 -1
- package/dist/helpers/convertX509PublicKeyToCOSE.js.map +0 -1
- package/dist/helpers/cose.js.map +0 -1
- package/dist/helpers/decodeAttestationObject.js +0 -14
- package/dist/helpers/decodeAttestationObject.js.map +0 -1
- package/dist/helpers/decodeAuthenticatorExtensions.js.map +0 -1
- package/dist/helpers/decodeClientDataJSON.js +0 -14
- package/dist/helpers/decodeClientDataJSON.js.map +0 -1
- package/dist/helpers/decodeCredentialPublicKey.d.ts +0 -2
- package/dist/helpers/decodeCredentialPublicKey.js +0 -9
- package/dist/helpers/decodeCredentialPublicKey.js.map +0 -1
- package/dist/helpers/generateChallenge.d.ts +0 -4
- package/dist/helpers/generateChallenge.js.map +0 -1
- package/dist/helpers/getCertificateInfo.js.map +0 -1
- package/dist/helpers/index.d.ts +0 -22
- package/dist/helpers/index.js +0 -60
- package/dist/helpers/index.js.map +0 -1
- package/dist/helpers/isCertRevoked.js.map +0 -1
- package/dist/helpers/iso/index.js.map +0 -1
- package/dist/helpers/iso/isoBase64URL.js.map +0 -1
- package/dist/helpers/iso/isoCBOR.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/digest.js +0 -21
- package/dist/helpers/iso/isoCrypto/digest.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/getRandomValues.js +0 -18
- package/dist/helpers/iso/isoCrypto/getRandomValues.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/importKey.js +0 -13
- package/dist/helpers/iso/isoCrypto/importKey.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/index.d.ts +0 -3
- package/dist/helpers/iso/isoCrypto/index.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/structs.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/unwrapEC2Signature.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/verify.js +0 -28
- package/dist/helpers/iso/isoCrypto/verify.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/verifyEC2.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/verifyOKP.js.map +0 -1
- package/dist/helpers/iso/isoCrypto/verifyRSA.js.map +0 -1
- package/dist/helpers/iso/isoUint8Array.js.map +0 -1
- package/dist/helpers/logging.js.map +0 -1
- package/dist/helpers/mapX509SignatureAlgToCOSEAlg.js.map +0 -1
- package/dist/helpers/matchExpectedRPID.js.map +0 -1
- package/dist/helpers/parseAuthenticatorData.js.map +0 -1
- package/dist/helpers/parseBackupFlags.js.map +0 -1
- package/dist/helpers/toHash.js.map +0 -1
- package/dist/helpers/validateCertificatePath.js.map +0 -1
- package/dist/helpers/verifySignature.js +0 -33
- package/dist/helpers/verifySignature.js.map +0 -1
- package/dist/index.d.ts +0 -17
- package/dist/index.js +0 -20
- package/dist/index.js.map +0 -1
- package/dist/metadata/mdsTypes.js.map +0 -1
- package/dist/metadata/parseJWT.js.map +0 -1
- package/dist/metadata/verifyAttestationWithMetadata.js.map +0 -1
- package/dist/metadata/verifyJWT.js +0 -42
- package/dist/metadata/verifyJWT.js.map +0 -1
- package/dist/registration/generateRegistrationOptions.js.map +0 -1
- package/dist/registration/verifications/tpm/constants.js.map +0 -1
- package/dist/registration/verifications/tpm/parseCertInfo.js.map +0 -1
- package/dist/registration/verifications/tpm/parsePubArea.js.map +0 -1
- package/dist/registration/verifications/tpm/verifyAttestationTPM.js.map +0 -1
- package/dist/registration/verifications/verifyAttestationAndroidKey.js.map +0 -1
- package/dist/registration/verifications/verifyAttestationAndroidSafetyNet.js.map +0 -1
- package/dist/registration/verifications/verifyAttestationApple.js.map +0 -1
- package/dist/registration/verifications/verifyAttestationFIDOU2F.js.map +0 -1
- package/dist/registration/verifications/verifyAttestationPacked.js.map +0 -1
- package/dist/registration/verifyRegistrationResponse.js.map +0 -1
- package/dist/services/defaultRootCerts/android-key.js.map +0 -1
- package/dist/services/defaultRootCerts/android-safetynet.js.map +0 -1
- package/dist/services/defaultRootCerts/apple.js.map +0 -1
- package/dist/services/defaultRootCerts/mds.js.map +0 -1
- package/dist/services/metadataService.js.map +0 -1
- package/dist/services/settingsService.js.map +0 -1
- /package/{dist → esm}/helpers/convertAAGUIDToString.d.ts +0 -0
- /package/{dist → esm}/helpers/convertCOSEtoPKCS.d.ts +0 -0
- /package/{dist → esm}/helpers/convertPEMToBytes.d.ts +0 -0
- /package/{dist → esm}/helpers/decodeAuthenticatorExtensions.d.ts +0 -0
- /package/{dist → esm}/helpers/iso/isoBase64URL.d.ts +0 -0
- /package/{dist → esm}/helpers/iso/isoCrypto/importKey.d.ts +0 -0
- /package/{dist → esm}/helpers/iso/isoCrypto/structs.d.ts +0 -0
- /package/{dist → esm}/helpers/iso/isoCrypto/unwrapEC2Signature.d.ts +0 -0
- /package/{dist → esm}/helpers/iso/isoUint8Array.d.ts +0 -0
- /package/{dist → esm}/helpers/matchExpectedRPID.d.ts +0 -0
- /package/{dist → esm}/helpers/validateCertificatePath.d.ts +0 -0
- /package/{dist → esm}/metadata/parseJWT.d.ts +0 -0
- /package/{dist → esm}/metadata/verifyJWT.d.ts +0 -0
- /package/{dist → esm}/registration/verifications/tpm/constants.d.ts +0 -0
- /package/{dist → esm}/registration/verifications/tpm/parseCertInfo.d.ts +0 -0
- /package/{dist → esm}/registration/verifications/tpm/parsePubArea.d.ts +0 -0
- /package/{dist → esm}/services/defaultRootCerts/android-key.d.ts +0 -0
- /package/{dist → esm}/services/defaultRootCerts/android-safetynet.d.ts +0 -0
- /package/{dist → esm}/services/defaultRootCerts/apple.d.ts +0 -0
- /package/{dist → esm}/services/defaultRootCerts/mds.d.ts +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { AsnParser, Certificate, id_ce_keyDescription, KeyDescription } from '../../deps.js';
|
|
2
|
+
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM.js';
|
|
3
|
+
import { validateCertificatePath } from '../../helpers/validateCertificatePath.js';
|
|
4
|
+
import { verifySignature } from '../../helpers/verifySignature.js';
|
|
5
|
+
import { convertCOSEtoPKCS } from '../../helpers/convertCOSEtoPKCS.js';
|
|
6
|
+
import { isCOSEAlg } from '../../helpers/cose.js';
|
|
7
|
+
import { isoUint8Array } from '../../helpers/iso/index.js';
|
|
8
|
+
import { MetadataService } from '../../services/metadataService.js';
|
|
9
|
+
import { verifyAttestationWithMetadata } from '../../metadata/verifyAttestationWithMetadata.js';
|
|
10
|
+
/**
|
|
11
|
+
* Verify an attestation response with fmt 'android-key'
|
|
12
|
+
*/
|
|
13
|
+
export async function verifyAttestationAndroidKey(options) {
|
|
14
|
+
const { authData, clientDataHash, attStmt, credentialPublicKey, aaguid, rootCertificates, } = options;
|
|
15
|
+
const x5c = attStmt.get('x5c');
|
|
16
|
+
const sig = attStmt.get('sig');
|
|
17
|
+
const alg = attStmt.get('alg');
|
|
18
|
+
if (!x5c) {
|
|
19
|
+
throw new Error('No attestation certificate provided in attestation statement (AndroidKey)');
|
|
20
|
+
}
|
|
21
|
+
if (!sig) {
|
|
22
|
+
throw new Error('No attestation signature provided in attestation statement (AndroidKey)');
|
|
23
|
+
}
|
|
24
|
+
if (!alg) {
|
|
25
|
+
throw new Error(`Attestation statement did not contain alg (AndroidKey)`);
|
|
26
|
+
}
|
|
27
|
+
if (!isCOSEAlg(alg)) {
|
|
28
|
+
throw new Error(`Attestation statement contained invalid alg ${alg} (AndroidKey)`);
|
|
29
|
+
}
|
|
30
|
+
// Check that credentialPublicKey matches the public key in the attestation certificate
|
|
31
|
+
// Find the public cert in the certificate as PKCS
|
|
32
|
+
const parsedCert = AsnParser.parse(x5c[0], Certificate);
|
|
33
|
+
const parsedCertPubKey = new Uint8Array(parsedCert.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
|
|
34
|
+
// Convert the credentialPublicKey to PKCS
|
|
35
|
+
const credPubKeyPKCS = convertCOSEtoPKCS(credentialPublicKey);
|
|
36
|
+
if (!isoUint8Array.areEqual(credPubKeyPKCS, parsedCertPubKey)) {
|
|
37
|
+
throw new Error('Credential public key does not equal leaf cert public key (AndroidKey)');
|
|
38
|
+
}
|
|
39
|
+
// Find Android KeyStore Extension in certificate extensions
|
|
40
|
+
const extKeyStore = parsedCert.tbsCertificate.extensions?.find((ext) => ext.extnID === id_ce_keyDescription);
|
|
41
|
+
if (!extKeyStore) {
|
|
42
|
+
throw new Error('Certificate did not contain extKeyStore (AndroidKey)');
|
|
43
|
+
}
|
|
44
|
+
const parsedExtKeyStore = AsnParser.parse(extKeyStore.extnValue, KeyDescription);
|
|
45
|
+
// Verify extKeyStore values
|
|
46
|
+
const { attestationChallenge, teeEnforced, softwareEnforced } = parsedExtKeyStore;
|
|
47
|
+
if (!isoUint8Array.areEqual(new Uint8Array(attestationChallenge.buffer), clientDataHash)) {
|
|
48
|
+
throw new Error('Attestation challenge was not equal to client data hash (AndroidKey)');
|
|
49
|
+
}
|
|
50
|
+
// Ensure that the key is strictly bound to the caller app identifier (shouldn't contain the
|
|
51
|
+
// [600] tag)
|
|
52
|
+
if (teeEnforced.allApplications !== undefined) {
|
|
53
|
+
throw new Error('teeEnforced contained "allApplications [600]" tag (AndroidKey)');
|
|
54
|
+
}
|
|
55
|
+
if (softwareEnforced.allApplications !== undefined) {
|
|
56
|
+
throw new Error('teeEnforced contained "allApplications [600]" tag (AndroidKey)');
|
|
57
|
+
}
|
|
58
|
+
const statement = await MetadataService.getStatement(aaguid);
|
|
59
|
+
if (statement) {
|
|
60
|
+
try {
|
|
61
|
+
await verifyAttestationWithMetadata({
|
|
62
|
+
statement,
|
|
63
|
+
credentialPublicKey,
|
|
64
|
+
x5c,
|
|
65
|
+
attestationStatementAlg: alg,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const _err = err;
|
|
70
|
+
throw new Error(`${_err.message} (AndroidKey)`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
try {
|
|
75
|
+
// Try validating the certificate path using the root certificates set via SettingsService
|
|
76
|
+
await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
const _err = err;
|
|
80
|
+
throw new Error(`${_err.message} (AndroidKey)`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const signatureBase = isoUint8Array.concat([authData, clientDataHash]);
|
|
84
|
+
return verifySignature({
|
|
85
|
+
signature: sig,
|
|
86
|
+
data: signatureBase,
|
|
87
|
+
x509Certificate: x5c[0],
|
|
88
|
+
hashAlgorithm: alg,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { toHash } from '../../helpers/toHash.js';
|
|
2
|
+
import { verifySignature } from '../../helpers/verifySignature.js';
|
|
3
|
+
import { getCertificateInfo } from '../../helpers/getCertificateInfo.js';
|
|
4
|
+
import { validateCertificatePath } from '../../helpers/validateCertificatePath.js';
|
|
5
|
+
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM.js';
|
|
6
|
+
import { isoBase64URL, isoUint8Array } from '../../helpers/iso/index.js';
|
|
7
|
+
import { MetadataService } from '../../services/metadataService.js';
|
|
8
|
+
import { verifyAttestationWithMetadata } from '../../metadata/verifyAttestationWithMetadata.js';
|
|
9
|
+
/**
|
|
10
|
+
* Verify an attestation response with fmt 'android-safetynet'
|
|
11
|
+
*/
|
|
12
|
+
export async function verifyAttestationAndroidSafetyNet(options) {
|
|
13
|
+
const { attStmt, clientDataHash, authData, aaguid, rootCertificates, verifyTimestampMS = true, credentialPublicKey, } = options;
|
|
14
|
+
const alg = attStmt.get('alg');
|
|
15
|
+
const response = attStmt.get('response');
|
|
16
|
+
const ver = attStmt.get('ver');
|
|
17
|
+
if (!ver) {
|
|
18
|
+
throw new Error('No ver value in attestation (SafetyNet)');
|
|
19
|
+
}
|
|
20
|
+
if (!response) {
|
|
21
|
+
throw new Error('No response was included in attStmt by authenticator (SafetyNet)');
|
|
22
|
+
}
|
|
23
|
+
// Prepare to verify a JWT
|
|
24
|
+
const jwt = isoUint8Array.toUTF8String(response);
|
|
25
|
+
const jwtParts = jwt.split('.');
|
|
26
|
+
const HEADER = JSON.parse(isoBase64URL.toString(jwtParts[0]));
|
|
27
|
+
const PAYLOAD = JSON.parse(isoBase64URL.toString(jwtParts[1]));
|
|
28
|
+
const SIGNATURE = jwtParts[2];
|
|
29
|
+
/**
|
|
30
|
+
* START Verify PAYLOAD
|
|
31
|
+
*/
|
|
32
|
+
const { nonce, ctsProfileMatch, timestampMs } = PAYLOAD;
|
|
33
|
+
if (verifyTimestampMS) {
|
|
34
|
+
// Make sure timestamp is in the past
|
|
35
|
+
let now = Date.now();
|
|
36
|
+
if (timestampMs > Date.now()) {
|
|
37
|
+
throw new Error(`Payload timestamp "${timestampMs}" was later than "${now}" (SafetyNet)`);
|
|
38
|
+
}
|
|
39
|
+
// Consider a SafetyNet attestation valid within a minute of it being performed
|
|
40
|
+
const timestampPlusDelay = timestampMs + 60 * 1000;
|
|
41
|
+
now = Date.now();
|
|
42
|
+
if (timestampPlusDelay < now) {
|
|
43
|
+
throw new Error(`Payload timestamp "${timestampPlusDelay}" has expired (SafetyNet)`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const nonceBase = isoUint8Array.concat([authData, clientDataHash]);
|
|
47
|
+
const nonceBuffer = await toHash(nonceBase);
|
|
48
|
+
const expectedNonce = isoBase64URL.fromBuffer(nonceBuffer, 'base64');
|
|
49
|
+
if (nonce !== expectedNonce) {
|
|
50
|
+
throw new Error('Could not verify payload nonce (SafetyNet)');
|
|
51
|
+
}
|
|
52
|
+
if (!ctsProfileMatch) {
|
|
53
|
+
throw new Error('Could not verify device integrity (SafetyNet)');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* END Verify PAYLOAD
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* START Verify Header
|
|
60
|
+
*/
|
|
61
|
+
// `HEADER.x5c[0]` is definitely a base64 string
|
|
62
|
+
const leafCertBuffer = isoBase64URL.toBuffer(HEADER.x5c[0], 'base64');
|
|
63
|
+
const leafCertInfo = getCertificateInfo(leafCertBuffer);
|
|
64
|
+
const { subject } = leafCertInfo;
|
|
65
|
+
// Ensure the certificate was issued to this hostname
|
|
66
|
+
// See https://developer.android.com/training/safetynet/attestation#verify-attestation-response
|
|
67
|
+
if (subject.CN !== 'attest.android.com') {
|
|
68
|
+
throw new Error('Certificate common name was not "attest.android.com" (SafetyNet)');
|
|
69
|
+
}
|
|
70
|
+
const statement = await MetadataService.getStatement(aaguid);
|
|
71
|
+
if (statement) {
|
|
72
|
+
try {
|
|
73
|
+
await verifyAttestationWithMetadata({
|
|
74
|
+
statement,
|
|
75
|
+
credentialPublicKey,
|
|
76
|
+
x5c: HEADER.x5c,
|
|
77
|
+
attestationStatementAlg: alg,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const _err = err;
|
|
82
|
+
throw new Error(`${_err.message} (SafetyNet)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
try {
|
|
87
|
+
// Try validating the certificate path using the root certificates set via SettingsService
|
|
88
|
+
await validateCertificatePath(HEADER.x5c.map(convertCertBufferToPEM), rootCertificates);
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const _err = err;
|
|
92
|
+
throw new Error(`${_err.message} (SafetyNet)`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* END Verify Header
|
|
97
|
+
*/
|
|
98
|
+
/**
|
|
99
|
+
* START Verify Signature
|
|
100
|
+
*/
|
|
101
|
+
const signatureBaseBuffer = isoUint8Array.fromUTF8String(`${jwtParts[0]}.${jwtParts[1]}`);
|
|
102
|
+
const signatureBuffer = isoBase64URL.toBuffer(SIGNATURE);
|
|
103
|
+
const verified = await verifySignature({
|
|
104
|
+
signature: signatureBuffer,
|
|
105
|
+
data: signatureBaseBuffer,
|
|
106
|
+
x509Certificate: leafCertBuffer,
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* END Verify Signature
|
|
110
|
+
*/
|
|
111
|
+
return verified;
|
|
112
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { AttestationFormatVerifierOpts } from '../verifyRegistrationResponse';
|
|
1
|
+
import type { AttestationFormatVerifierOpts } from '../verifyRegistrationResponse.js';
|
|
2
2
|
export declare function verifyAttestationApple(options: AttestationFormatVerifierOpts): Promise<boolean>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { AsnParser, Certificate } from '../../deps.js';
|
|
2
|
+
import { validateCertificatePath } from '../../helpers/validateCertificatePath.js';
|
|
3
|
+
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM.js';
|
|
4
|
+
import { toHash } from '../../helpers/toHash.js';
|
|
5
|
+
import { convertCOSEtoPKCS } from '../../helpers/convertCOSEtoPKCS.js';
|
|
6
|
+
import { isoUint8Array } from '../../helpers/iso/index.js';
|
|
7
|
+
export async function verifyAttestationApple(options) {
|
|
8
|
+
const { attStmt, authData, clientDataHash, credentialPublicKey, rootCertificates, } = options;
|
|
9
|
+
const x5c = attStmt.get('x5c');
|
|
10
|
+
if (!x5c) {
|
|
11
|
+
throw new Error('No attestation certificate provided in attestation statement (Apple)');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Verify certificate path
|
|
15
|
+
*/
|
|
16
|
+
try {
|
|
17
|
+
await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
const _err = err;
|
|
21
|
+
throw new Error(`${_err.message} (Apple)`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compare nonce in certificate extension to computed nonce
|
|
25
|
+
*/
|
|
26
|
+
const parsedCredCert = AsnParser.parse(x5c[0], Certificate);
|
|
27
|
+
const { extensions, subjectPublicKeyInfo } = parsedCredCert.tbsCertificate;
|
|
28
|
+
if (!extensions) {
|
|
29
|
+
throw new Error('credCert missing extensions (Apple)');
|
|
30
|
+
}
|
|
31
|
+
const extCertNonce = extensions.find((ext) => ext.extnID === '1.2.840.113635.100.8.2');
|
|
32
|
+
if (!extCertNonce) {
|
|
33
|
+
throw new Error('credCert missing "1.2.840.113635.100.8.2" extension (Apple)');
|
|
34
|
+
}
|
|
35
|
+
const nonceToHash = isoUint8Array.concat([authData, clientDataHash]);
|
|
36
|
+
const nonce = await toHash(nonceToHash);
|
|
37
|
+
/**
|
|
38
|
+
* Ignore the first six ASN.1 structure bytes that define the nonce as an OCTET STRING. Should
|
|
39
|
+
* trim off <Buffer 30 24 a1 22 04 20>
|
|
40
|
+
*
|
|
41
|
+
* TODO: Try and get @peculiar (GitHub) to add a schema for "1.2.840.113635.100.8.2" when we
|
|
42
|
+
* find out where it's defined (doesn't seem to be publicly documented at the moment...)
|
|
43
|
+
*/
|
|
44
|
+
const extNonce = new Uint8Array(extCertNonce.extnValue.buffer).slice(6);
|
|
45
|
+
if (!isoUint8Array.areEqual(nonce, extNonce)) {
|
|
46
|
+
throw new Error(`credCert nonce was not expected value (Apple)`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Verify credential public key matches the Subject Public Key of credCert
|
|
50
|
+
*/
|
|
51
|
+
const credPubKeyPKCS = convertCOSEtoPKCS(credentialPublicKey);
|
|
52
|
+
const credCertSubjectPublicKey = new Uint8Array(subjectPublicKeyInfo.subjectPublicKey);
|
|
53
|
+
if (!isoUint8Array.areEqual(credPubKeyPKCS, credCertSubjectPublicKey)) {
|
|
54
|
+
throw new Error('Credential public key does not equal credCert public key (Apple)');
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { convertCOSEtoPKCS } from '../../helpers/convertCOSEtoPKCS.js';
|
|
2
|
+
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM.js';
|
|
3
|
+
import { validateCertificatePath } from '../../helpers/validateCertificatePath.js';
|
|
4
|
+
import { verifySignature } from '../../helpers/verifySignature.js';
|
|
5
|
+
import { isoUint8Array } from '../../helpers/iso/index.js';
|
|
6
|
+
import { COSEALG } from '../../helpers/cose.js';
|
|
7
|
+
/**
|
|
8
|
+
* Verify an attestation response with fmt 'fido-u2f'
|
|
9
|
+
*/
|
|
10
|
+
export async function verifyAttestationFIDOU2F(options) {
|
|
11
|
+
const { attStmt, clientDataHash, rpIdHash, credentialID, credentialPublicKey, aaguid, rootCertificates, } = options;
|
|
12
|
+
const reservedByte = Uint8Array.from([0x00]);
|
|
13
|
+
const publicKey = convertCOSEtoPKCS(credentialPublicKey);
|
|
14
|
+
const signatureBase = isoUint8Array.concat([
|
|
15
|
+
reservedByte,
|
|
16
|
+
rpIdHash,
|
|
17
|
+
clientDataHash,
|
|
18
|
+
credentialID,
|
|
19
|
+
publicKey,
|
|
20
|
+
]);
|
|
21
|
+
const sig = attStmt.get('sig');
|
|
22
|
+
const x5c = attStmt.get('x5c');
|
|
23
|
+
if (!x5c) {
|
|
24
|
+
throw new Error('No attestation certificate provided in attestation statement (FIDOU2F)');
|
|
25
|
+
}
|
|
26
|
+
if (!sig) {
|
|
27
|
+
throw new Error('No attestation signature provided in attestation statement (FIDOU2F)');
|
|
28
|
+
}
|
|
29
|
+
// FIDO spec says that aaguid _must_ equal 0x00 here to be legit
|
|
30
|
+
const aaguidToHex = Number.parseInt(isoUint8Array.toHex(aaguid), 16);
|
|
31
|
+
if (aaguidToHex !== 0x00) {
|
|
32
|
+
throw new Error(`AAGUID "${aaguidToHex}" was not expected value`);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// Try validating the certificate path using the root certificates set via SettingsService
|
|
36
|
+
await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const _err = err;
|
|
40
|
+
throw new Error(`${_err.message} (FIDOU2F)`);
|
|
41
|
+
}
|
|
42
|
+
return verifySignature({
|
|
43
|
+
signature: sig,
|
|
44
|
+
data: signatureBase,
|
|
45
|
+
x509Certificate: x5c[0],
|
|
46
|
+
hashAlgorithm: COSEALG.ES256,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { isCOSEAlg } from '../../helpers/cose.js';
|
|
2
|
+
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM.js';
|
|
3
|
+
import { validateCertificatePath } from '../../helpers/validateCertificatePath.js';
|
|
4
|
+
import { getCertificateInfo } from '../../helpers/getCertificateInfo.js';
|
|
5
|
+
import { verifySignature } from '../../helpers/verifySignature.js';
|
|
6
|
+
import { isoUint8Array } from '../../helpers/iso/index.js';
|
|
7
|
+
import { MetadataService } from '../../services/metadataService.js';
|
|
8
|
+
import { verifyAttestationWithMetadata } from '../../metadata/verifyAttestationWithMetadata.js';
|
|
9
|
+
/**
|
|
10
|
+
* Verify an attestation response with fmt 'packed'
|
|
11
|
+
*/
|
|
12
|
+
export async function verifyAttestationPacked(options) {
|
|
13
|
+
const { attStmt, clientDataHash, authData, credentialPublicKey, aaguid, rootCertificates, } = options;
|
|
14
|
+
const sig = attStmt.get('sig');
|
|
15
|
+
const x5c = attStmt.get('x5c');
|
|
16
|
+
const alg = attStmt.get('alg');
|
|
17
|
+
if (!sig) {
|
|
18
|
+
throw new Error('No attestation signature provided in attestation statement (Packed)');
|
|
19
|
+
}
|
|
20
|
+
if (!alg) {
|
|
21
|
+
throw new Error('Attestation statement did not contain alg (Packed)');
|
|
22
|
+
}
|
|
23
|
+
if (!isCOSEAlg(alg)) {
|
|
24
|
+
throw new Error(`Attestation statement contained invalid alg ${alg} (Packed)`);
|
|
25
|
+
}
|
|
26
|
+
const signatureBase = isoUint8Array.concat([authData, clientDataHash]);
|
|
27
|
+
let verified = false;
|
|
28
|
+
if (x5c) {
|
|
29
|
+
const { subject, basicConstraintsCA, version, notBefore, notAfter } = getCertificateInfo(x5c[0]);
|
|
30
|
+
const { OU, CN, O, C } = subject;
|
|
31
|
+
if (OU !== 'Authenticator Attestation') {
|
|
32
|
+
throw new Error('Certificate OU was not "Authenticator Attestation" (Packed|Full)');
|
|
33
|
+
}
|
|
34
|
+
if (!CN) {
|
|
35
|
+
throw new Error('Certificate CN was empty (Packed|Full)');
|
|
36
|
+
}
|
|
37
|
+
if (!O) {
|
|
38
|
+
throw new Error('Certificate O was empty (Packed|Full)');
|
|
39
|
+
}
|
|
40
|
+
if (!C || C.length !== 2) {
|
|
41
|
+
throw new Error('Certificate C was not two-character ISO 3166 code (Packed|Full)');
|
|
42
|
+
}
|
|
43
|
+
if (basicConstraintsCA) {
|
|
44
|
+
throw new Error('Certificate basic constraints CA was not `false` (Packed|Full)');
|
|
45
|
+
}
|
|
46
|
+
if (version !== 2) {
|
|
47
|
+
throw new Error('Certificate version was not `3` (ASN.1 value of 2) (Packed|Full)');
|
|
48
|
+
}
|
|
49
|
+
let now = new Date();
|
|
50
|
+
if (notBefore > now) {
|
|
51
|
+
throw new Error(`Certificate not good before "${notBefore.toString()}" (Packed|Full)`);
|
|
52
|
+
}
|
|
53
|
+
now = new Date();
|
|
54
|
+
if (notAfter < now) {
|
|
55
|
+
throw new Error(`Certificate not good after "${notAfter.toString()}" (Packed|Full)`);
|
|
56
|
+
}
|
|
57
|
+
// TODO: If certificate contains id-fido-gen-ce-aaguid(1.3.6.1.4.1.45724.1.1.4) extension, check
|
|
58
|
+
// that it’s value is set to the same AAGUID as in authData.
|
|
59
|
+
// If available, validate attestation alg and x5c with info in the metadata statement
|
|
60
|
+
const statement = await MetadataService.getStatement(aaguid);
|
|
61
|
+
if (statement) {
|
|
62
|
+
// The presence of x5c means this is a full attestation. Check to see if attestationTypes
|
|
63
|
+
// includes packed attestations.
|
|
64
|
+
if (statement.attestationTypes.indexOf('basic_full') < 0) {
|
|
65
|
+
throw new Error('Metadata does not indicate support for full attestations (Packed|Full)');
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
await verifyAttestationWithMetadata({
|
|
69
|
+
statement,
|
|
70
|
+
credentialPublicKey,
|
|
71
|
+
x5c,
|
|
72
|
+
attestationStatementAlg: alg,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const _err = err;
|
|
77
|
+
throw new Error(`${_err.message} (Packed|Full)`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
try {
|
|
82
|
+
// Try validating the certificate path using the root certificates set via SettingsService
|
|
83
|
+
await validateCertificatePath(x5c.map(convertCertBufferToPEM), rootCertificates);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const _err = err;
|
|
87
|
+
throw new Error(`${_err.message} (Packed|Full)`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
verified = await verifySignature({
|
|
91
|
+
signature: sig,
|
|
92
|
+
data: signatureBase,
|
|
93
|
+
x509Certificate: x5c[0],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
verified = await verifySignature({
|
|
98
|
+
signature: sig,
|
|
99
|
+
data: signatureBase,
|
|
100
|
+
credentialPublicKey,
|
|
101
|
+
hashAlgorithm: alg,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return verified;
|
|
105
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject';
|
|
3
|
-
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions';
|
|
1
|
+
import type { COSEAlgorithmIdentifier, CredentialDeviceType, RegistrationResponseJSON } from '../deps.js';
|
|
2
|
+
import { AttestationFormat, AttestationStatement } from '../helpers/decodeAttestationObject.js';
|
|
3
|
+
import { AuthenticationExtensionsAuthenticatorOutputs } from '../helpers/decodeAuthenticatorExtensions.js';
|
|
4
4
|
export type VerifyRegistrationResponseOpts = {
|
|
5
5
|
response: RegistrationResponseJSON;
|
|
6
6
|
expectedChallenge: string | ((challenge: string) => boolean);
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { decodeAttestationObject, } from '../helpers/decodeAttestationObject.js';
|
|
2
|
+
import { decodeClientDataJSON } from '../helpers/decodeClientDataJSON.js';
|
|
3
|
+
import { parseAuthenticatorData } from '../helpers/parseAuthenticatorData.js';
|
|
4
|
+
import { toHash } from '../helpers/toHash.js';
|
|
5
|
+
import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey.js';
|
|
6
|
+
import { COSEKEYS } from '../helpers/cose.js';
|
|
7
|
+
import { convertAAGUIDToString } from '../helpers/convertAAGUIDToString.js';
|
|
8
|
+
import { parseBackupFlags } from '../helpers/parseBackupFlags.js';
|
|
9
|
+
import { matchExpectedRPID } from '../helpers/matchExpectedRPID.js';
|
|
10
|
+
import { isoBase64URL } from '../helpers/iso/index.js';
|
|
11
|
+
import { SettingsService } from '../services/settingsService.js';
|
|
12
|
+
import { supportedCOSEAlgorithmIdentifiers } from './generateRegistrationOptions.js';
|
|
13
|
+
import { verifyAttestationFIDOU2F } from './verifications/verifyAttestationFIDOU2F.js';
|
|
14
|
+
import { verifyAttestationPacked } from './verifications/verifyAttestationPacked.js';
|
|
15
|
+
import { verifyAttestationAndroidSafetyNet } from './verifications/verifyAttestationAndroidSafetyNet.js';
|
|
16
|
+
import { verifyAttestationTPM } from './verifications/tpm/verifyAttestationTPM.js';
|
|
17
|
+
import { verifyAttestationAndroidKey } from './verifications/verifyAttestationAndroidKey.js';
|
|
18
|
+
import { verifyAttestationApple } from './verifications/verifyAttestationApple.js';
|
|
19
|
+
/**
|
|
20
|
+
* Verify that the user has legitimately completed the registration process
|
|
21
|
+
*
|
|
22
|
+
* **Options:**
|
|
23
|
+
*
|
|
24
|
+
* @param response Response returned by **@simplewebauthn/browser**'s `startAuthentication()`
|
|
25
|
+
* @param expectedChallenge The base64url-encoded `options.challenge` returned by
|
|
26
|
+
* `generateRegistrationOptions()`
|
|
27
|
+
* @param expectedOrigin Website URL (or array of URLs) that the registration should have occurred on
|
|
28
|
+
* @param expectedRPID RP ID (or array of IDs) that was specified in the registration options
|
|
29
|
+
* @param requireUserVerification (Optional) Enforce user verification by the authenticator
|
|
30
|
+
* (via PIN, fingerprint, etc...)
|
|
31
|
+
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
32
|
+
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
33
|
+
*/
|
|
34
|
+
export async function verifyRegistrationResponse(options) {
|
|
35
|
+
const { response, expectedChallenge, expectedOrigin, expectedRPID, requireUserVerification = true, supportedAlgorithmIDs = supportedCOSEAlgorithmIdentifiers, } = options;
|
|
36
|
+
const { id, rawId, type: credentialType, response: attestationResponse } = response;
|
|
37
|
+
// Ensure credential specified an ID
|
|
38
|
+
if (!id) {
|
|
39
|
+
throw new Error('Missing credential ID');
|
|
40
|
+
}
|
|
41
|
+
// Ensure ID is base64url-encoded
|
|
42
|
+
if (id !== rawId) {
|
|
43
|
+
throw new Error('Credential ID was not base64url-encoded');
|
|
44
|
+
}
|
|
45
|
+
// Make sure credential type is public-key
|
|
46
|
+
if (credentialType !== 'public-key') {
|
|
47
|
+
throw new Error(`Unexpected credential type ${credentialType}, expected "public-key"`);
|
|
48
|
+
}
|
|
49
|
+
const clientDataJSON = decodeClientDataJSON(attestationResponse.clientDataJSON);
|
|
50
|
+
const { type, origin, challenge, tokenBinding } = clientDataJSON;
|
|
51
|
+
// Make sure we're handling an registration
|
|
52
|
+
if (type !== 'webauthn.create') {
|
|
53
|
+
throw new Error(`Unexpected registration response type: ${type}`);
|
|
54
|
+
}
|
|
55
|
+
// Ensure the device provided the challenge we gave it
|
|
56
|
+
if (typeof expectedChallenge === 'function') {
|
|
57
|
+
if (!expectedChallenge(challenge)) {
|
|
58
|
+
throw new Error(`Custom challenge verifier returned false for registration response challenge "${challenge}"`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (challenge !== expectedChallenge) {
|
|
62
|
+
throw new Error(`Unexpected registration response challenge "${challenge}", expected "${expectedChallenge}"`);
|
|
63
|
+
}
|
|
64
|
+
// Check that the origin is our site
|
|
65
|
+
if (Array.isArray(expectedOrigin)) {
|
|
66
|
+
if (!expectedOrigin.includes(origin)) {
|
|
67
|
+
throw new Error(`Unexpected registration response origin "${origin}", expected one of: ${expectedOrigin.join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
if (origin !== expectedOrigin) {
|
|
72
|
+
throw new Error(`Unexpected registration response origin "${origin}", expected "${expectedOrigin}"`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (tokenBinding) {
|
|
76
|
+
if (typeof tokenBinding !== 'object') {
|
|
77
|
+
throw new Error(`Unexpected value for TokenBinding "${tokenBinding}"`);
|
|
78
|
+
}
|
|
79
|
+
if (['present', 'supported', 'not-supported'].indexOf(tokenBinding.status) < 0) {
|
|
80
|
+
throw new Error(`Unexpected tokenBinding.status value of "${tokenBinding.status}"`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const attestationObject = isoBase64URL.toBuffer(attestationResponse.attestationObject);
|
|
84
|
+
const decodedAttestationObject = decodeAttestationObject(attestationObject);
|
|
85
|
+
const fmt = decodedAttestationObject.get('fmt');
|
|
86
|
+
const authData = decodedAttestationObject.get('authData');
|
|
87
|
+
const attStmt = decodedAttestationObject.get('attStmt');
|
|
88
|
+
const parsedAuthData = parseAuthenticatorData(authData);
|
|
89
|
+
const { aaguid, rpIdHash, flags, credentialID, counter, credentialPublicKey, extensionsData, } = parsedAuthData;
|
|
90
|
+
// Make sure the response's RP ID is ours
|
|
91
|
+
let matchedRPID;
|
|
92
|
+
if (expectedRPID) {
|
|
93
|
+
let expectedRPIDs = [];
|
|
94
|
+
if (typeof expectedRPID === 'string') {
|
|
95
|
+
expectedRPIDs = [expectedRPID];
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
expectedRPIDs = expectedRPID;
|
|
99
|
+
}
|
|
100
|
+
matchedRPID = await matchExpectedRPID(rpIdHash, expectedRPIDs);
|
|
101
|
+
}
|
|
102
|
+
// Make sure someone was physically present
|
|
103
|
+
if (!flags.up) {
|
|
104
|
+
throw new Error('User not present during registration');
|
|
105
|
+
}
|
|
106
|
+
// Enforce user verification if specified
|
|
107
|
+
if (requireUserVerification && !flags.uv) {
|
|
108
|
+
throw new Error('User verification required, but user could not be verified');
|
|
109
|
+
}
|
|
110
|
+
if (!credentialID) {
|
|
111
|
+
throw new Error('No credential ID was provided by authenticator');
|
|
112
|
+
}
|
|
113
|
+
if (!credentialPublicKey) {
|
|
114
|
+
throw new Error('No public key was provided by authenticator');
|
|
115
|
+
}
|
|
116
|
+
if (!aaguid) {
|
|
117
|
+
throw new Error('No AAGUID was present during registration');
|
|
118
|
+
}
|
|
119
|
+
const decodedPublicKey = decodeCredentialPublicKey(credentialPublicKey);
|
|
120
|
+
const alg = decodedPublicKey.get(COSEKEYS.alg);
|
|
121
|
+
if (typeof alg !== 'number') {
|
|
122
|
+
throw new Error('Credential public key was missing numeric alg');
|
|
123
|
+
}
|
|
124
|
+
// Make sure the key algorithm is one we specified within the registration options
|
|
125
|
+
if (!supportedAlgorithmIDs.includes(alg)) {
|
|
126
|
+
const supported = supportedAlgorithmIDs.join(', ');
|
|
127
|
+
throw new Error(`Unexpected public key alg "${alg}", expected one of "${supported}"`);
|
|
128
|
+
}
|
|
129
|
+
const clientDataHash = await toHash(isoBase64URL.toBuffer(attestationResponse.clientDataJSON));
|
|
130
|
+
const rootCertificates = SettingsService.getRootCertificates({
|
|
131
|
+
identifier: fmt,
|
|
132
|
+
});
|
|
133
|
+
// Prepare arguments to pass to the relevant verification method
|
|
134
|
+
const verifierOpts = {
|
|
135
|
+
aaguid,
|
|
136
|
+
attStmt,
|
|
137
|
+
authData,
|
|
138
|
+
clientDataHash,
|
|
139
|
+
credentialID,
|
|
140
|
+
credentialPublicKey,
|
|
141
|
+
rootCertificates,
|
|
142
|
+
rpIdHash,
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Verification can only be performed when attestation = 'direct'
|
|
146
|
+
*/
|
|
147
|
+
let verified = false;
|
|
148
|
+
if (fmt === 'fido-u2f') {
|
|
149
|
+
verified = await verifyAttestationFIDOU2F(verifierOpts);
|
|
150
|
+
}
|
|
151
|
+
else if (fmt === 'packed') {
|
|
152
|
+
verified = await verifyAttestationPacked(verifierOpts);
|
|
153
|
+
}
|
|
154
|
+
else if (fmt === 'android-safetynet') {
|
|
155
|
+
verified = await verifyAttestationAndroidSafetyNet(verifierOpts);
|
|
156
|
+
}
|
|
157
|
+
else if (fmt === 'android-key') {
|
|
158
|
+
verified = await verifyAttestationAndroidKey(verifierOpts);
|
|
159
|
+
}
|
|
160
|
+
else if (fmt === 'tpm') {
|
|
161
|
+
verified = await verifyAttestationTPM(verifierOpts);
|
|
162
|
+
}
|
|
163
|
+
else if (fmt === 'apple') {
|
|
164
|
+
verified = await verifyAttestationApple(verifierOpts);
|
|
165
|
+
}
|
|
166
|
+
else if (fmt === 'none') {
|
|
167
|
+
if (attStmt.size > 0) {
|
|
168
|
+
throw new Error('None attestation had unexpected attestation statement');
|
|
169
|
+
}
|
|
170
|
+
// This is the weaker of the attestations, so there's nothing else to really check
|
|
171
|
+
verified = true;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
throw new Error(`Unsupported Attestation Format: ${fmt}`);
|
|
175
|
+
}
|
|
176
|
+
const toReturn = {
|
|
177
|
+
verified,
|
|
178
|
+
};
|
|
179
|
+
if (toReturn.verified) {
|
|
180
|
+
const { credentialDeviceType, credentialBackedUp } = parseBackupFlags(flags);
|
|
181
|
+
toReturn.registrationInfo = {
|
|
182
|
+
fmt,
|
|
183
|
+
counter,
|
|
184
|
+
aaguid: convertAAGUIDToString(aaguid),
|
|
185
|
+
credentialID,
|
|
186
|
+
credentialPublicKey,
|
|
187
|
+
credentialType,
|
|
188
|
+
attestationObject,
|
|
189
|
+
userVerified: flags.uv,
|
|
190
|
+
credentialDeviceType,
|
|
191
|
+
credentialBackedUp,
|
|
192
|
+
origin: clientDataJSON.origin,
|
|
193
|
+
rpID: matchedRPID,
|
|
194
|
+
authenticatorExtensionResults: extensionsData,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return toReturn;
|
|
198
|
+
}
|