Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/webauthn/authenticator_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AuthenticatorData
SIGN_COUNT_POSITION = RP_ID_HASH_LENGTH + FLAGS_LENGTH

USER_PRESENT_FLAG_POSITION = 0
USER_VERIFIED_FLAG_POSITION = 2
ATTESTED_CREDENTIAL_DATA_INCLUDED_FLAG_POSITION = 6

def initialize(data)
Expand All @@ -29,10 +30,18 @@ def valid?
end
end

def user_flagged?
user_present? || user_verified?
end

def user_present?
flags[USER_PRESENT_FLAG_POSITION] == "1"
end

def user_verified?
flags[USER_VERIFIED_FLAG_POSITION] == "1"
end

def attested_credential_data_included?
flags[ATTESTED_CREDENTIAL_DATA_INCLUDED_FLAG_POSITION] == "1"
end
Expand Down
2 changes: 1 addition & 1 deletion lib/webauthn/authenticator_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def valid?(original_challenge, original_origin)
valid_origin?(original_origin) &&
valid_rp_id?(original_origin) &&
authenticator_data.valid? &&
authenticator_data.user_present?
authenticator_data.user_flagged?
end

def client_data
Expand Down
14 changes: 3 additions & 11 deletions spec/support/fake_authenticator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def rp_id_hash
attr_reader :challenge, :context, :rp_id

def raw_flags
["#{user_present_bit}00000#{attested_credential_data_present_bit}0"].pack("b*")
["#{bit(:user_present)}0#{bit(:user_verified)}000#{attested_credential_data_present_bit}0"].pack("b*")
end

def attested_credential_data_present_bit
Expand All @@ -53,22 +53,14 @@ def raw_sign_count
[@sign_count].pack('L>')
end

def user_present_bit
if user_present?
def bit(flag)
if context[flag].nil? || context[flag]
"1"
else
"0"
end
end

def user_present?
if context[:user_present].nil?
true
else
context[:user_present]
end
end

def origin
@origin ||= context[:origin] || fake_origin
end
Expand Down
4 changes: 2 additions & 2 deletions spec/webauthn/authenticator_assertion_response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@
let(:authenticator) do
FakeAuthenticator::Get.new(
challenge: original_challenge,
context: { origin: original_origin, user_present: false }
context: { origin: original_origin, user_present: false, user_verified: false }
)
end

it "is invalid if user-present flag is off" do
it "is invalid if user flags are off" do
expect(
assertion_response.valid?(
original_challenge,
Expand Down
62 changes: 58 additions & 4 deletions spec/webauthn/authenticator_data_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

RSpec.describe WebAuthn::AuthenticatorData do
let(:authenticator) do
FakeAuthenticator::Base.new(rp_id: rp_id, sign_count: sign_count, context: { user_present: user_presence })
FakeAuthenticator::Base.new(
rp_id: rp_id,
sign_count: sign_count,
context: { user_present: user_present, user_verified: user_verified }
)
end

let(:rp_id) { "localhost" }
let(:sign_count) { 42 }
let(:user_presence) { true }
let(:user_present) { true }
let(:user_verified) { false }

let(:authenticator_data) { described_class.new(authenticator.authenticator_data) }

Expand All @@ -23,13 +28,62 @@

describe "#user_present?" do
subject { authenticator_data.user_present? }

context "when UP flag is set" do
let(:user_presence) { true }
let(:user_present) { true }
it { is_expected.to be_truthy }
end

context "when UP flag is not set" do
let(:user_presence) { false }
let(:user_present) { false }
it { is_expected.to be_falsy }
end
end

describe "#user_verified?" do
subject { authenticator_data.user_verified? }

context "when UV flag is set" do
let(:user_verified) { true }

it { is_expected.to be_truthy }
end

context "when UV flag is not set" do
let(:user_verified) { false }

it { is_expected.to be_falsy }
end
end

describe "#user_flagged?" do
subject { authenticator_data.user_flagged? }

context "when both UP and UV flag are set" do
let(:user_present) { true }
let(:user_verified) { true }

it { is_expected.to be_truthy }
end

context "when only UP is set" do
let(:user_present) { true }
let(:user_verified) { false }

it { is_expected.to be_truthy }
end

context "when only UV flag is set" do
let(:user_present) { false }
let(:user_verified) { true }

it { is_expected.to be_truthy }
end

context "when both UP and UV flag are not set" do
let(:user_present) { false }
let(:user_verified) { false }

it { is_expected.to be_falsy }
end
end
Expand Down