FIX: Catch error when unknown COSE algorithm is supplied for Security Key (#8649)

Added a fix to gracefully error with a Webauthn::SecurityKeyError if somehow a user provides an unkown COSE algorithm when logging in with a security key.

If `COSE::Algorithm.find` returns nil we now fail gracefully and log the algorithm used along with the user ID and the security key params for debugging, as this will help us find other common algorithms to implement for webauthn
This commit is contained in:
Martin Brennan
2020-01-02 10:14:22 +10:00
committed by GitHub
parent 57081acc08
commit c031434b86
4 changed files with 22 additions and 1 deletions

View File

@ -943,6 +943,7 @@ en:
public_key_error: "The public key verification for the credential failed." public_key_error: "The public key verification for the credential failed."
ownership_error: "The security key is not owned by the user." ownership_error: "The security key is not owned by the user."
not_found_error: "A security key with the provided credential ID could not be found." not_found_error: "A security key with the provided credential ID could not be found."
unknown_cose_algorithm_error: "The algorithm used for the security key is not recognized."
topic_flag_types: topic_flag_types:
spam: spam:

View File

@ -26,4 +26,5 @@ module Webauthn
class NotFoundError < SecurityKeyError; end class NotFoundError < SecurityKeyError; end
class OwnershipError < SecurityKeyError; end class OwnershipError < SecurityKeyError; end
class PublicKeyError < SecurityKeyError; end class PublicKeyError < SecurityKeyError; end
class UnknownCOSEAlgorithmError < SecurityKeyError; end
end end

View File

@ -64,7 +64,14 @@ module Webauthn
# 17. Using credentialPublicKey, verify that sig is a valid signature over the binary concatenation of authData and hash. # 17. Using credentialPublicKey, verify that sig is a valid signature over the binary concatenation of authData and hash.
cose_key = COSE::Key.deserialize(Base64.decode64(security_key.public_key)) cose_key = COSE::Key.deserialize(Base64.decode64(security_key.public_key))
if !cose_key.to_pkey.verify(COSE::Algorithm.find(cose_key.alg).hash_function, signature, auth_data + client_data_hash) cose_algorithm = COSE::Algorithm.find(cose_key.alg)
if cose_algorithm.blank?
Rails.logger.error("Unknown COSE algorithm encountered. alg: #{cose_key.alg}. user_id: #{@current_user.id}. params: #{@params.inspect}")
raise(UnknownCOSEAlgorithmError, I18n.t('webauthn.validation.unknown_cose_algorithm_error'))
end
if !cose_key.to_pkey.verify(cose_algorithm.hash_function, signature, auth_data + client_data_hash)
raise(PublicKeyError, I18n.t('webauthn.validation.public_key_error')) raise(PublicKeyError, I18n.t('webauthn.validation.public_key_error'))
end end

View File

@ -131,4 +131,16 @@ describe Webauthn::SecurityKeyAuthenticationService do
) )
end end
end end
context 'when the COSE algorithm used cannot be found' do
before do
COSE::Algorithm.expects(:find).returns(nil)
end
it 'raises a UnknownCOSEAlgorithmError' do
expect { subject.authenticate_security_key }.to raise_error(
Webauthn::UnknownCOSEAlgorithmError, I18n.t('webauthn.validation.unknown_cose_algorithm_error')
)
end
end
end end