@simplewebauthn/server 7.4.0 → 8.0.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 +20 -7
- 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 +11 -0
- package/esm/deps.js +14 -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 -42
- 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 +11 -0
- package/script/deps.js +71 -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 +9 -13
- 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,122 @@
|
|
|
1
|
+
import { AsnSerializer } from '../deps.js';
|
|
2
|
+
import { isCertRevoked } from './isCertRevoked.js';
|
|
3
|
+
import { verifySignature } from './verifySignature.js';
|
|
4
|
+
import { mapX509SignatureAlgToCOSEAlg } from './mapX509SignatureAlgToCOSEAlg.js';
|
|
5
|
+
import { getCertificateInfo } from './getCertificateInfo.js';
|
|
6
|
+
import { convertPEMToBytes } from './convertPEMToBytes.js';
|
|
7
|
+
/**
|
|
8
|
+
* Traverse an array of PEM certificates and ensure they form a proper chain
|
|
9
|
+
* @param certificates Typically the result of `x5c.map(convertASN1toPEM)`
|
|
10
|
+
* @param rootCertificates Possible root certificates to complete the path
|
|
11
|
+
*/
|
|
12
|
+
export async function validateCertificatePath(certificates, rootCertificates = []) {
|
|
13
|
+
if (rootCertificates.length === 0) {
|
|
14
|
+
// We have no root certs with which to create a full path, so skip path validation
|
|
15
|
+
// TODO: Is this going to be acceptable default behavior??
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
let invalidSubjectAndIssuerError = false;
|
|
19
|
+
let certificateNotYetValidOrExpiredErrorMessage = undefined;
|
|
20
|
+
for (const rootCert of rootCertificates) {
|
|
21
|
+
try {
|
|
22
|
+
const certsWithRoot = certificates.concat([rootCert]);
|
|
23
|
+
await _validatePath(certsWithRoot);
|
|
24
|
+
// If we successfully validated a path then there's no need to continue. Reset any existing
|
|
25
|
+
// errors that were thrown by earlier root certificates
|
|
26
|
+
invalidSubjectAndIssuerError = false;
|
|
27
|
+
certificateNotYetValidOrExpiredErrorMessage = undefined;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err instanceof InvalidSubjectAndIssuer) {
|
|
32
|
+
invalidSubjectAndIssuerError = true;
|
|
33
|
+
}
|
|
34
|
+
else if (err instanceof CertificateNotYetValidOrExpired) {
|
|
35
|
+
certificateNotYetValidOrExpiredErrorMessage = err.message;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// We tried multiple root certs and none of them worked
|
|
43
|
+
if (invalidSubjectAndIssuerError) {
|
|
44
|
+
throw new InvalidSubjectAndIssuer();
|
|
45
|
+
}
|
|
46
|
+
else if (certificateNotYetValidOrExpiredErrorMessage) {
|
|
47
|
+
throw new CertificateNotYetValidOrExpired(certificateNotYetValidOrExpiredErrorMessage);
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
async function _validatePath(certificates) {
|
|
52
|
+
if (new Set(certificates).size !== certificates.length) {
|
|
53
|
+
throw new Error('Invalid certificate path: found duplicate certificates');
|
|
54
|
+
}
|
|
55
|
+
// From leaf to root, make sure each cert is issued by the next certificate in the chain
|
|
56
|
+
for (let i = 0; i < certificates.length; i += 1) {
|
|
57
|
+
const subjectPem = certificates[i];
|
|
58
|
+
const isLeafCert = i === 0;
|
|
59
|
+
const isRootCert = i + 1 >= certificates.length;
|
|
60
|
+
let issuerPem = '';
|
|
61
|
+
if (isRootCert) {
|
|
62
|
+
issuerPem = subjectPem;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
issuerPem = certificates[i + 1];
|
|
66
|
+
}
|
|
67
|
+
const subjectInfo = getCertificateInfo(convertPEMToBytes(subjectPem));
|
|
68
|
+
const issuerInfo = getCertificateInfo(convertPEMToBytes(issuerPem));
|
|
69
|
+
const x509Subject = subjectInfo.parsedCertificate;
|
|
70
|
+
// Check for certificate revocation
|
|
71
|
+
const subjectCertRevoked = await isCertRevoked(x509Subject);
|
|
72
|
+
if (subjectCertRevoked) {
|
|
73
|
+
throw new Error(`Found revoked certificate in certificate path`);
|
|
74
|
+
}
|
|
75
|
+
// Check that intermediate certificate is within its valid time window
|
|
76
|
+
const { notBefore, notAfter } = issuerInfo;
|
|
77
|
+
const now = new Date(Date.now());
|
|
78
|
+
if (notBefore > now || notAfter < now) {
|
|
79
|
+
if (isLeafCert) {
|
|
80
|
+
throw new CertificateNotYetValidOrExpired(`Leaf certificate is not yet valid or expired: ${issuerPem}`);
|
|
81
|
+
}
|
|
82
|
+
else if (isRootCert) {
|
|
83
|
+
throw new CertificateNotYetValidOrExpired(`Root certificate is not yet valid or expired: ${issuerPem}`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw new CertificateNotYetValidOrExpired(`Intermediate certificate is not yet valid or expired: ${issuerPem}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (subjectInfo.issuer.combined !== issuerInfo.subject.combined) {
|
|
90
|
+
throw new InvalidSubjectAndIssuer();
|
|
91
|
+
}
|
|
92
|
+
// Verify the subject certificate's signature with the issuer cert's public key
|
|
93
|
+
const data = AsnSerializer.serialize(x509Subject.tbsCertificate);
|
|
94
|
+
const signature = x509Subject.signatureValue;
|
|
95
|
+
const signatureAlgorithm = mapX509SignatureAlgToCOSEAlg(x509Subject.signatureAlgorithm.algorithm);
|
|
96
|
+
const issuerCertBytes = convertPEMToBytes(issuerPem);
|
|
97
|
+
const verified = await verifySignature({
|
|
98
|
+
data: new Uint8Array(data),
|
|
99
|
+
signature: new Uint8Array(signature),
|
|
100
|
+
x509Certificate: issuerCertBytes,
|
|
101
|
+
hashAlgorithm: signatureAlgorithm,
|
|
102
|
+
});
|
|
103
|
+
if (!verified) {
|
|
104
|
+
throw new Error('Invalid certificate path: invalid signature');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
// Custom errors to help pass on certain errors
|
|
110
|
+
class InvalidSubjectAndIssuer extends Error {
|
|
111
|
+
constructor() {
|
|
112
|
+
const message = 'Subject issuer did not match issuer subject';
|
|
113
|
+
super(message);
|
|
114
|
+
this.name = 'InvalidSubjectAndIssuer';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
class CertificateNotYetValidOrExpired extends Error {
|
|
118
|
+
constructor(message) {
|
|
119
|
+
super(message);
|
|
120
|
+
this.name = 'CertificateNotYetValidOrExpired';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { COSEALG } from './cose';
|
|
1
|
+
import { COSEALG } from './cose.js';
|
|
2
2
|
/**
|
|
3
3
|
* Verify an authenticator's signature
|
|
4
4
|
*/
|
|
@@ -9,3 +9,6 @@ export declare function verifySignature(opts: {
|
|
|
9
9
|
x509Certificate?: Uint8Array;
|
|
10
10
|
hashAlgorithm?: COSEALG;
|
|
11
11
|
}): Promise<boolean>;
|
|
12
|
+
export declare const _verifySignatureInternals: {
|
|
13
|
+
stubThis: (value: Promise<boolean>) => Promise<boolean>;
|
|
14
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isoCrypto } from './iso/index.js';
|
|
2
|
+
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey.js';
|
|
3
|
+
import { convertX509PublicKeyToCOSE } from './convertX509PublicKeyToCOSE.js';
|
|
4
|
+
/**
|
|
5
|
+
* Verify an authenticator's signature
|
|
6
|
+
*/
|
|
7
|
+
export function verifySignature(opts) {
|
|
8
|
+
const { signature, data, credentialPublicKey, x509Certificate, hashAlgorithm, } = opts;
|
|
9
|
+
if (!x509Certificate && !credentialPublicKey) {
|
|
10
|
+
throw new Error('Must declare either "leafCert" or "credentialPublicKey"');
|
|
11
|
+
}
|
|
12
|
+
if (x509Certificate && credentialPublicKey) {
|
|
13
|
+
throw new Error('Must not declare both "leafCert" and "credentialPublicKey"');
|
|
14
|
+
}
|
|
15
|
+
let cosePublicKey = new Map();
|
|
16
|
+
if (credentialPublicKey) {
|
|
17
|
+
cosePublicKey = decodeCredentialPublicKey(credentialPublicKey);
|
|
18
|
+
}
|
|
19
|
+
else if (x509Certificate) {
|
|
20
|
+
cosePublicKey = convertX509PublicKeyToCOSE(x509Certificate);
|
|
21
|
+
}
|
|
22
|
+
return _verifySignatureInternals.stubThis(isoCrypto.verify({
|
|
23
|
+
cosePublicKey,
|
|
24
|
+
signature,
|
|
25
|
+
data,
|
|
26
|
+
shaHashOverride: hashAlgorithm,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
// Make it possible to stub the return value during testing
|
|
30
|
+
export const _verifySignatureInternals = {
|
|
31
|
+
stubThis: (value) => value,
|
|
32
|
+
};
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module @simplewebauthn/server
|
|
4
|
+
*/
|
|
5
|
+
import { generateRegistrationOptions } from './registration/generateRegistrationOptions.js';
|
|
6
|
+
import { verifyRegistrationResponse } from './registration/verifyRegistrationResponse.js';
|
|
7
|
+
import { generateAuthenticationOptions } from './authentication/generateAuthenticationOptions.js';
|
|
8
|
+
import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse.js';
|
|
9
|
+
import { MetadataService } from './services/metadataService.js';
|
|
10
|
+
import { SettingsService } from './services/settingsService.js';
|
|
11
|
+
export { generateAuthenticationOptions, generateRegistrationOptions, MetadataService, SettingsService, verifyAuthenticationResponse, verifyRegistrationResponse, };
|
|
12
|
+
import type { GenerateRegistrationOptionsOpts } from './registration/generateRegistrationOptions.js';
|
|
13
|
+
import type { GenerateAuthenticationOptionsOpts } from './authentication/generateAuthenticationOptions.js';
|
|
14
|
+
import type { MetadataStatement } from './metadata/mdsTypes.js';
|
|
15
|
+
import type { VerifiedRegistrationResponse, VerifyRegistrationResponseOpts } from './registration/verifyRegistrationResponse.js';
|
|
16
|
+
import type { VerifiedAuthenticationResponse, VerifyAuthenticationResponseOpts } from './authentication/verifyAuthenticationResponse.js';
|
|
17
|
+
export type { GenerateAuthenticationOptionsOpts, GenerateRegistrationOptionsOpts, MetadataStatement, VerifiedAuthenticationResponse, VerifiedRegistrationResponse, VerifyAuthenticationResponseOpts, VerifyRegistrationResponseOpts, };
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* @module @simplewebauthn/server
|
|
4
|
+
*/
|
|
5
|
+
import { generateRegistrationOptions } from './registration/generateRegistrationOptions.js';
|
|
6
|
+
import { verifyRegistrationResponse } from './registration/verifyRegistrationResponse.js';
|
|
7
|
+
import { generateAuthenticationOptions } from './authentication/generateAuthenticationOptions.js';
|
|
8
|
+
import { verifyAuthenticationResponse } from './authentication/verifyAuthenticationResponse.js';
|
|
9
|
+
import { MetadataService } from './services/metadataService.js';
|
|
10
|
+
import { SettingsService } from './services/settingsService.js';
|
|
11
|
+
export { generateAuthenticationOptions, generateRegistrationOptions, MetadataService, SettingsService, verifyAuthenticationResponse, verifyRegistrationResponse, };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const AlgSign = [
|
|
2
|
+
'secp256r1_ecdsa_sha256_raw',
|
|
3
|
+
'secp256r1_ecdsa_sha256_der',
|
|
4
|
+
'rsassa_pss_sha256_raw',
|
|
5
|
+
'rsassa_pss_sha256_der',
|
|
6
|
+
'secp256k1_ecdsa_sha256_raw',
|
|
7
|
+
'secp256k1_ecdsa_sha256_der',
|
|
8
|
+
'rsassa_pss_sha384_raw',
|
|
9
|
+
'rsassa_pkcsv15_sha256_raw',
|
|
10
|
+
'rsassa_pkcsv15_sha384_raw',
|
|
11
|
+
'rsassa_pkcsv15_sha512_raw',
|
|
12
|
+
'rsassa_pkcsv15_sha1_raw',
|
|
13
|
+
'secp384r1_ecdsa_sha384_raw',
|
|
14
|
+
'secp512r1_ecdsa_sha256_raw',
|
|
15
|
+
'ed25519_eddsa_sha512_raw',
|
|
16
|
+
];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isoBase64URL } from '../helpers/iso/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Process a JWT into Javascript-friendly data structures
|
|
4
|
+
*/
|
|
5
|
+
export function parseJWT(jwt) {
|
|
6
|
+
const parts = jwt.split('.');
|
|
7
|
+
return [
|
|
8
|
+
JSON.parse(isoBase64URL.toString(parts[0])),
|
|
9
|
+
JSON.parse(isoBase64URL.toString(parts[1])),
|
|
10
|
+
parts[2],
|
|
11
|
+
];
|
|
12
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Base64URLString } from '
|
|
2
|
-
import type {
|
|
3
|
-
import { COSEALG, COSECRV, COSEKTY } from '../helpers/cose';
|
|
1
|
+
import type { Base64URLString } from '../deps.js';
|
|
2
|
+
import type { AlgSign, MetadataStatement } from './mdsTypes.js';
|
|
3
|
+
import { COSEALG, COSECRV, COSEKTY } from '../helpers/cose.js';
|
|
4
4
|
/**
|
|
5
5
|
* Match properties of the authenticator's attestation statement against expected values as
|
|
6
6
|
* registered with the FIDO Alliance Metadata Service
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM.js';
|
|
2
|
+
import { validateCertificatePath } from '../helpers/validateCertificatePath.js';
|
|
3
|
+
import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey.js';
|
|
4
|
+
import { COSEKEYS, COSEKTY, isCOSEPublicKeyEC2 } from '../helpers/cose.js';
|
|
5
|
+
/**
|
|
6
|
+
* Match properties of the authenticator's attestation statement against expected values as
|
|
7
|
+
* registered with the FIDO Alliance Metadata Service
|
|
8
|
+
*/
|
|
9
|
+
export async function verifyAttestationWithMetadata({ statement, credentialPublicKey, x5c, attestationStatementAlg, }) {
|
|
10
|
+
const { authenticationAlgorithms, authenticatorGetInfo, attestationRootCertificates, } = statement;
|
|
11
|
+
// Make sure the alg in the attestation statement matches one of the ones specified in metadata
|
|
12
|
+
const keypairCOSEAlgs = new Set();
|
|
13
|
+
authenticationAlgorithms.forEach((algSign) => {
|
|
14
|
+
// Map algSign string to { kty, alg, crv }
|
|
15
|
+
const algSignCOSEINFO = algSignToCOSEInfoMap[algSign];
|
|
16
|
+
// Keeping this statement here just in case MDS returns something unexpected
|
|
17
|
+
if (algSignCOSEINFO) {
|
|
18
|
+
keypairCOSEAlgs.add(algSignCOSEINFO);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
// Extract the public key's COSE info for comparison
|
|
22
|
+
const decodedPublicKey = decodeCredentialPublicKey(credentialPublicKey);
|
|
23
|
+
const kty = decodedPublicKey.get(COSEKEYS.kty);
|
|
24
|
+
const alg = decodedPublicKey.get(COSEKEYS.alg);
|
|
25
|
+
if (!kty) {
|
|
26
|
+
throw new Error('Credential public key was missing kty');
|
|
27
|
+
}
|
|
28
|
+
if (!alg) {
|
|
29
|
+
throw new Error('Credential public key was missing alg');
|
|
30
|
+
}
|
|
31
|
+
if (!kty) {
|
|
32
|
+
throw new Error('Credential public key was missing kty');
|
|
33
|
+
}
|
|
34
|
+
// Assume everything is a number because these values should be
|
|
35
|
+
const publicKeyCOSEInfo = { kty, alg };
|
|
36
|
+
if (isCOSEPublicKeyEC2(decodedPublicKey)) {
|
|
37
|
+
const crv = decodedPublicKey.get(COSEKEYS.crv);
|
|
38
|
+
publicKeyCOSEInfo.crv = crv;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Attempt to match the credential public key's algorithm to one specified in the device's
|
|
42
|
+
* metadata
|
|
43
|
+
*/
|
|
44
|
+
let foundMatch = false;
|
|
45
|
+
for (const keypairAlg of keypairCOSEAlgs) {
|
|
46
|
+
// Make sure algorithm and key type match
|
|
47
|
+
if (keypairAlg.alg === publicKeyCOSEInfo.alg &&
|
|
48
|
+
keypairAlg.kty === publicKeyCOSEInfo.kty) {
|
|
49
|
+
// If not an RSA keypair then make sure curve numbers match too
|
|
50
|
+
if ((keypairAlg.kty === COSEKTY.EC2 || keypairAlg.kty === COSEKTY.OKP) &&
|
|
51
|
+
keypairAlg.crv === publicKeyCOSEInfo.crv) {
|
|
52
|
+
foundMatch = true;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// We've matched an RSA public key's properties
|
|
56
|
+
foundMatch = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (foundMatch) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Make sure the public key is one of the allowed algorithms
|
|
64
|
+
if (!foundMatch) {
|
|
65
|
+
/**
|
|
66
|
+
* Craft some useful error output from the MDS algorithms
|
|
67
|
+
*
|
|
68
|
+
* Example:
|
|
69
|
+
*
|
|
70
|
+
* ```
|
|
71
|
+
* [
|
|
72
|
+
* 'rsassa_pss_sha256_raw' (COSE info: { kty: 3, alg: -37 }),
|
|
73
|
+
* 'secp256k1_ecdsa_sha256_raw' (COSE info: { kty: 2, alg: -47, crv: 8 })
|
|
74
|
+
* ]
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
const debugMDSAlgs = authenticationAlgorithms.map((algSign) => `'${algSign}' (COSE info: ${stringifyCOSEInfo(algSignToCOSEInfoMap[algSign])})`);
|
|
78
|
+
const strMDSAlgs = JSON.stringify(debugMDSAlgs, null, 2).replace(/"/g, '');
|
|
79
|
+
/**
|
|
80
|
+
* Construct useful error output about the public key
|
|
81
|
+
*/
|
|
82
|
+
const strPubKeyAlg = stringifyCOSEInfo(publicKeyCOSEInfo);
|
|
83
|
+
throw new Error(`Public key parameters ${strPubKeyAlg} did not match any of the following metadata algorithms:\n${strMDSAlgs}`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Confirm the attestation statement's algorithm is one supported according to metadata
|
|
87
|
+
*/
|
|
88
|
+
if (attestationStatementAlg !== undefined &&
|
|
89
|
+
authenticatorGetInfo?.algorithms !== undefined) {
|
|
90
|
+
const getInfoAlgs = authenticatorGetInfo.algorithms.map((_alg) => _alg.alg);
|
|
91
|
+
if (getInfoAlgs.indexOf(attestationStatementAlg) < 0) {
|
|
92
|
+
throw new Error(`Attestation statement alg ${attestationStatementAlg} did not match one of ${getInfoAlgs}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Prepare to check the certificate chain
|
|
96
|
+
const authenticatorCerts = x5c.map(convertCertBufferToPEM);
|
|
97
|
+
const statementRootCerts = attestationRootCertificates.map(convertCertBufferToPEM);
|
|
98
|
+
/**
|
|
99
|
+
* If an authenticator returns exactly one certificate in its x5c, and that cert is found in the
|
|
100
|
+
* metadata statement then the authenticator is "self-referencing". In this case we forego
|
|
101
|
+
* certificate chain validation.
|
|
102
|
+
*/
|
|
103
|
+
let authenticatorIsSelfReferencing = false;
|
|
104
|
+
if (authenticatorCerts.length === 1 &&
|
|
105
|
+
statementRootCerts.indexOf(authenticatorCerts[0]) >= 0) {
|
|
106
|
+
authenticatorIsSelfReferencing = true;
|
|
107
|
+
}
|
|
108
|
+
if (!authenticatorIsSelfReferencing) {
|
|
109
|
+
try {
|
|
110
|
+
await validateCertificatePath(authenticatorCerts, statementRootCerts);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
const _err = err;
|
|
114
|
+
throw new Error(`Could not validate certificate path with any metadata root certificates: ${_err.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Convert ALG_SIGN values to COSE info
|
|
121
|
+
*
|
|
122
|
+
* Values pulled from `ALG_KEY_COSE` definitions in the FIDO Registry of Predefined Values
|
|
123
|
+
*
|
|
124
|
+
* https://fidoalliance.org/specs/common-specs/fido-registry-v2.2-ps-20220523.html#authentication-algorithms
|
|
125
|
+
*/
|
|
126
|
+
export const algSignToCOSEInfoMap = {
|
|
127
|
+
secp256r1_ecdsa_sha256_raw: { kty: 2, alg: -7, crv: 1 },
|
|
128
|
+
secp256r1_ecdsa_sha256_der: { kty: 2, alg: -7, crv: 1 },
|
|
129
|
+
rsassa_pss_sha256_raw: { kty: 3, alg: -37 },
|
|
130
|
+
rsassa_pss_sha256_der: { kty: 3, alg: -37 },
|
|
131
|
+
secp256k1_ecdsa_sha256_raw: { kty: 2, alg: -47, crv: 8 },
|
|
132
|
+
secp256k1_ecdsa_sha256_der: { kty: 2, alg: -47, crv: 8 },
|
|
133
|
+
rsassa_pss_sha384_raw: { kty: 3, alg: -38 },
|
|
134
|
+
rsassa_pkcsv15_sha256_raw: { kty: 3, alg: -257 },
|
|
135
|
+
rsassa_pkcsv15_sha384_raw: { kty: 3, alg: -258 },
|
|
136
|
+
rsassa_pkcsv15_sha512_raw: { kty: 3, alg: -259 },
|
|
137
|
+
rsassa_pkcsv15_sha1_raw: { kty: 3, alg: -65535 },
|
|
138
|
+
secp384r1_ecdsa_sha384_raw: { kty: 2, alg: -35, crv: 2 },
|
|
139
|
+
secp512r1_ecdsa_sha256_raw: { kty: 2, alg: -36, crv: 3 },
|
|
140
|
+
ed25519_eddsa_sha512_raw: { kty: 1, alg: -8, crv: 6 },
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* A helper to format COSEInfo a little nicer than we can achieve with JSON.stringify()
|
|
144
|
+
*
|
|
145
|
+
* Input: `{ "kty": 3, "alg": -257 }`
|
|
146
|
+
*
|
|
147
|
+
* Output: `"{ kty: 3, alg: -257 }"`
|
|
148
|
+
*/
|
|
149
|
+
function stringifyCOSEInfo(info) {
|
|
150
|
+
const { kty, alg, crv } = info;
|
|
151
|
+
let toReturn = '';
|
|
152
|
+
if (kty !== COSEKTY.RSA) {
|
|
153
|
+
toReturn = `{ kty: ${kty}, alg: ${alg}, crv: ${crv} }`;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
toReturn = `{ kty: ${kty}, alg: ${alg} }`;
|
|
157
|
+
}
|
|
158
|
+
return toReturn;
|
|
159
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { convertX509PublicKeyToCOSE } from '../helpers/convertX509PublicKeyToCOSE.js';
|
|
2
|
+
import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.js';
|
|
3
|
+
import { COSEALG, COSEKEYS, isCOSEPublicKeyEC2, isCOSEPublicKeyRSA } from '../helpers/cose.js';
|
|
4
|
+
import { verifyEC2 } from '../helpers/iso/isoCrypto/verifyEC2.js';
|
|
5
|
+
import { verifyRSA } from '../helpers/iso/isoCrypto/verifyRSA.js';
|
|
6
|
+
/**
|
|
7
|
+
* Lightweight verification for FIDO MDS JWTs. Supports use of EC2 and RSA.
|
|
8
|
+
*
|
|
9
|
+
* If this ever needs to support more JWS algorithms, here's the list of them:
|
|
10
|
+
*
|
|
11
|
+
* https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1
|
|
12
|
+
*
|
|
13
|
+
* (Pulled from https://www.rfc-editor.org/rfc/rfc7515#section-4.1.1)
|
|
14
|
+
*/
|
|
15
|
+
export function verifyJWT(jwt, leafCert) {
|
|
16
|
+
const [header, payload, signature] = jwt.split('.');
|
|
17
|
+
const certCOSE = convertX509PublicKeyToCOSE(leafCert);
|
|
18
|
+
const data = isoUint8Array.fromUTF8String(`${header}.${payload}`);
|
|
19
|
+
const signatureBytes = isoBase64URL.toBuffer(signature);
|
|
20
|
+
if (isCOSEPublicKeyEC2(certCOSE)) {
|
|
21
|
+
return verifyEC2({
|
|
22
|
+
data,
|
|
23
|
+
signature: signatureBytes,
|
|
24
|
+
cosePublicKey: certCOSE,
|
|
25
|
+
shaHashOverride: COSEALG.ES256,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
else if (isCOSEPublicKeyRSA(certCOSE)) {
|
|
29
|
+
return verifyRSA({
|
|
30
|
+
data,
|
|
31
|
+
signature: signatureBytes,
|
|
32
|
+
cosePublicKey: certCOSE,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const kty = certCOSE.get(COSEKEYS.kty);
|
|
36
|
+
throw new Error(`JWT verification with public key of kty ${kty} is not supported by this method`);
|
|
37
|
+
}
|
package/esm/package.json
ADDED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialDescriptorFuture } from '
|
|
1
|
+
import type { AttestationConveyancePreference, AuthenticationExtensionsClientInputs, AuthenticatorSelectionCriteria, COSEAlgorithmIdentifier, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialDescriptorFuture } from '../deps.js';
|
|
2
2
|
export type GenerateRegistrationOptionsOpts = {
|
|
3
3
|
rpName: string;
|
|
4
4
|
rpID: string;
|
|
@@ -40,4 +40,4 @@ export declare const supportedCOSEAlgorithmIdentifiers: COSEAlgorithmIdentifier[
|
|
|
40
40
|
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
41
41
|
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
42
42
|
*/
|
|
43
|
-
export declare function generateRegistrationOptions(options: GenerateRegistrationOptionsOpts): PublicKeyCredentialCreationOptionsJSON
|
|
43
|
+
export declare function generateRegistrationOptions(options: GenerateRegistrationOptionsOpts): Promise<PublicKeyCredentialCreationOptionsJSON>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { generateChallenge } from '../helpers/generateChallenge.js';
|
|
2
|
+
import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Supported crypto algo identifiers
|
|
5
|
+
* See https://w3c.github.io/webauthn/#sctn-alg-identifier
|
|
6
|
+
* and https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
7
|
+
*/
|
|
8
|
+
export const supportedCOSEAlgorithmIdentifiers = [
|
|
9
|
+
// EdDSA (In first position to encourage authenticators to use this over ES256)
|
|
10
|
+
-8,
|
|
11
|
+
// ECDSA w/ SHA-256
|
|
12
|
+
-7,
|
|
13
|
+
// ECDSA w/ SHA-512
|
|
14
|
+
-36,
|
|
15
|
+
// RSASSA-PSS w/ SHA-256
|
|
16
|
+
-37,
|
|
17
|
+
// RSASSA-PSS w/ SHA-384
|
|
18
|
+
-38,
|
|
19
|
+
// RSASSA-PSS w/ SHA-512
|
|
20
|
+
-39,
|
|
21
|
+
// RSASSA-PKCS1-v1_5 w/ SHA-256
|
|
22
|
+
-257,
|
|
23
|
+
// RSASSA-PKCS1-v1_5 w/ SHA-384
|
|
24
|
+
-258,
|
|
25
|
+
// RSASSA-PKCS1-v1_5 w/ SHA-512
|
|
26
|
+
-259,
|
|
27
|
+
// RSASSA-PKCS1-v1_5 w/ SHA-1 (Deprecated; here for legacy support)
|
|
28
|
+
-65535,
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Set up some default authenticator selection options as per the latest spec:
|
|
32
|
+
* https://www.w3.org/TR/webauthn-2/#dictdef-authenticatorselectioncriteria
|
|
33
|
+
*
|
|
34
|
+
* Helps with some older platforms (e.g. Android 7.0 Nougat) that may not be aware of these
|
|
35
|
+
* defaults.
|
|
36
|
+
*/
|
|
37
|
+
const defaultAuthenticatorSelection = {
|
|
38
|
+
residentKey: 'preferred',
|
|
39
|
+
userVerification: 'preferred',
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Use the most commonly-supported algorithms
|
|
43
|
+
* See the following:
|
|
44
|
+
* - https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
45
|
+
* - https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-pubkeycredparams
|
|
46
|
+
*/
|
|
47
|
+
const defaultSupportedAlgorithmIDs = [-8, -7, -257];
|
|
48
|
+
/**
|
|
49
|
+
* Prepare a value to pass into navigator.credentials.create(...) for authenticator "registration"
|
|
50
|
+
*
|
|
51
|
+
* **Options:**
|
|
52
|
+
*
|
|
53
|
+
* @param rpName User-visible, "friendly" website/service name
|
|
54
|
+
* @param rpID Valid domain name (after `https://`)
|
|
55
|
+
* @param userID User's website-specific unique ID
|
|
56
|
+
* @param userName User's website-specific username (email, etc...)
|
|
57
|
+
* @param challenge Random value the authenticator needs to sign and pass back
|
|
58
|
+
* @param userDisplayName User's actual name
|
|
59
|
+
* @param timeout How long (in ms) the user can take to complete attestation
|
|
60
|
+
* @param attestationType Specific attestation statement
|
|
61
|
+
* @param excludeCredentials Authenticators registered by the user so the user can't register the
|
|
62
|
+
* same credential multiple times
|
|
63
|
+
* @param authenticatorSelection Advanced criteria for restricting the types of authenticators that
|
|
64
|
+
* may be used
|
|
65
|
+
* @param extensions Additional plugins the authenticator or browser should use during attestation
|
|
66
|
+
* @param supportedAlgorithmIDs Array of numeric COSE algorithm identifiers supported for
|
|
67
|
+
* attestation by this RP. See https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
|
68
|
+
*/
|
|
69
|
+
export async function generateRegistrationOptions(options) {
|
|
70
|
+
const { rpName, rpID, userID, userName, challenge = await generateChallenge(), userDisplayName = userName, timeout = 60000, attestationType = 'none', excludeCredentials = [], authenticatorSelection = defaultAuthenticatorSelection, extensions, supportedAlgorithmIDs = defaultSupportedAlgorithmIDs, } = options;
|
|
71
|
+
/**
|
|
72
|
+
* Prepare pubKeyCredParams from the array of algorithm ID's
|
|
73
|
+
*/
|
|
74
|
+
const pubKeyCredParams = supportedAlgorithmIDs.map((id) => ({
|
|
75
|
+
alg: id,
|
|
76
|
+
type: 'public-key',
|
|
77
|
+
}));
|
|
78
|
+
/**
|
|
79
|
+
* Capture some of the nuances of how `residentKey` and `requireResidentKey` how either is set
|
|
80
|
+
* depending on when either is defined in the options
|
|
81
|
+
*/
|
|
82
|
+
if (authenticatorSelection.residentKey === undefined) {
|
|
83
|
+
/**
|
|
84
|
+
* `residentKey`: "If no value is given then the effective value is `required` if
|
|
85
|
+
* requireResidentKey is true or `discouraged` if it is false or absent."
|
|
86
|
+
*
|
|
87
|
+
* See https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-residentkey
|
|
88
|
+
*/
|
|
89
|
+
if (authenticatorSelection.requireResidentKey) {
|
|
90
|
+
authenticatorSelection.residentKey = 'required';
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
/**
|
|
94
|
+
* FIDO Conformance v1.7.2 fails the first test if we do this, even though this is
|
|
95
|
+
* technically compatible with the WebAuthn L2 spec...
|
|
96
|
+
*/
|
|
97
|
+
// authenticatorSelection.residentKey = 'discouraged';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
/**
|
|
102
|
+
* `requireResidentKey`: "Relying Parties SHOULD set it to true if, and only if, residentKey is
|
|
103
|
+
* set to "required""
|
|
104
|
+
*
|
|
105
|
+
* Spec says this property defaults to `false` so we should still be okay to assign `false` too
|
|
106
|
+
*
|
|
107
|
+
* See https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-requireresidentkey
|
|
108
|
+
*/
|
|
109
|
+
authenticatorSelection.requireResidentKey = authenticatorSelection.residentKey === 'required';
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Preserve ability to specify `string` values for challenges
|
|
113
|
+
*/
|
|
114
|
+
let _challenge = challenge;
|
|
115
|
+
if (typeof _challenge === 'string') {
|
|
116
|
+
_challenge = isoUint8Array.fromASCIIString(_challenge);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
challenge: isoBase64URL.fromBuffer(_challenge),
|
|
120
|
+
rp: {
|
|
121
|
+
name: rpName,
|
|
122
|
+
id: rpID,
|
|
123
|
+
},
|
|
124
|
+
user: {
|
|
125
|
+
id: userID,
|
|
126
|
+
name: userName,
|
|
127
|
+
displayName: userDisplayName,
|
|
128
|
+
},
|
|
129
|
+
pubKeyCredParams,
|
|
130
|
+
timeout,
|
|
131
|
+
attestation: attestationType,
|
|
132
|
+
excludeCredentials: excludeCredentials.map((cred) => ({
|
|
133
|
+
...cred,
|
|
134
|
+
id: isoBase64URL.fromBuffer(cred.id),
|
|
135
|
+
})),
|
|
136
|
+
authenticatorSelection,
|
|
137
|
+
extensions: {
|
|
138
|
+
...extensions,
|
|
139
|
+
credProps: true,
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|